@cachly-dev/mcp-server 0.10.182 → 0.10.184
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/src/handlers/fedbrain.js +26 -26
- package/dist/src/index.js +44 -44
- package/dist/src/rangfolge-stellschrauben.js +1 -1
- package/dist/src/startwissen.js +16 -15
- package/glama.json +1 -1
- package/hooks/cachly-ambient-einblendung.mjs +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|

|
|
11
11
|
|
|
12
12
|
`@cachly-dev/mcp-server` connects [cachly](https://cachly.dev) to Claude Code, Cursor,
|
|
13
|
-
GitHub Copilot, Windsurf, Cline, Continue.dev and
|
|
13
|
+
GitHub Copilot, Windsurf, Cline, Continue.dev, Zed, Codex CLI and Gemini CLI over
|
|
14
14
|
[MCP](https://modelcontextprotocol.io). It offers 124 MCP tools. Your AI stores a
|
|
15
15
|
lesson after a fix, and finds it again when the same problem returns. Your Brain
|
|
16
16
|
(the store of your lessons) lives on EU servers.
|
|
@@ -104,6 +104,8 @@ entry points at this npm package.
|
|
|
104
104
|
|-------|---------------------|
|
|
105
105
|
| [Claude Code hooks: which event to use when](https://cachly.dev/docs/claude-code-hooks) | `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `Stop` and more, sorted by when they fire. What each one can block, add and change. |
|
|
106
106
|
| [A UserPromptSubmit hook for Claude Code](https://cachly.dev/docs/claude-code-hooks/userpromptsubmit) | The stdin JSON, `additionalContext`, a working Node script and five traps to avoid. |
|
|
107
|
+
| The same hooks in [VS Code and Copilot CLI](https://cachly.dev/docs/claude-code-hooks#vscode), [Codex CLI](https://cachly.dev/docs/claude-code-hooks#codex) and [Gemini CLI](https://cachly.dev/docs/claude-code-hooks#gemini) | Which event takes context in each editor, and the exact file `setup` writes there. |
|
|
108
|
+
| Comparisons: [Supermemory](https://cachly.dev/docs/cachly-vs-supermemory), [Zep](https://cachly.dev/docs/cachly-vs-zep), [claude-mem](https://cachly.dev/docs/cachly-vs-claude-mem), [Basic Memory](https://cachly.dev/docs/cachly-vs-basic-memory), [mem0](https://cachly.dev/docs/cachly-vs-mem0), [Letta](https://cachly.dev/docs/cachly-vs-letta) | Side by side, each row with its source and a visible date, including when the other product fits better. |
|
|
107
109
|
| [EU-hosted MCP server: what leaves your machine](https://cachly.dev/docs/eu-hosted-mcp-memory-server) | Where data lands: storage in Germany, embeddings in the EU, the network edge, and a checklist. |
|
|
108
110
|
| [Lessons learned for coding agents](https://cachly.dev/docs/coding-agent-lessons-learned) | How to write a lesson your agent finds again: symptom, decisive fact first, what failed, files, a check. With examples and a `LESSONS.md`. |
|
|
109
111
|
| [JetBrains plugin guide](https://cachly.dev/docs/jetbrains) | What the plugin does, and how Claude Code, Junie and JetBrains AI Assistant use the Brain. |
|
|
@@ -309,9 +311,11 @@ Manual snippets are in [Manual Setup](#manual-setup).
|
|
|
309
311
|
| Editor / client | Auto-setup | Config file written | Global config | Notes |
|
|
310
312
|
|---|---|---|---|---|
|
|
311
313
|
| **Claude Code** | yes | `~/.claude/mcp.json` + `.mcp.json` | yes, always | Without a key: test Brain on the first tool call; browser sign-in only as fallback |
|
|
312
|
-
| **Cursor** | yes, detected via `.cursor/` | `.cursor/mcp.json` | no | Project-level; restart Cursor after setup |
|
|
314
|
+
| **Cursor** | yes, detected via `.cursor/` | `.cursor/mcp.json`, hooks in `.cursor/hooks.json` | no | Project-level; restart Cursor after setup. Lessons arrive with the first tool call of a turn |
|
|
313
315
|
| **Windsurf** | yes, detected via `.windsurf/` | `.windsurf/mcp.json` | no | Project-level; restart Windsurf after setup |
|
|
314
|
-
| **VS Code + Copilot** | yes, detected via `.vscode/` | `.vscode/mcp.json` | no | Needs the VS Code MCP support or Copilot chat |
|
|
316
|
+
| **VS Code + Copilot** | yes, detected via `.vscode/` | `.vscode/mcp.json`, hooks in `.github/hooks/cachly-ambient.json` | no | Needs the VS Code MCP support or Copilot chat. Briefing at session start, lessons before each prompt |
|
|
317
|
+
| **Codex CLI** | hooks yes, detected via `~/.codex` | hooks in `.codex/hooks.json` | no | Trust `.codex/` and confirm the hook once in `/hooks`. For the tools, `init --editor codex` prints the `codex mcp add` line |
|
|
318
|
+
| **Gemini CLI** | hooks yes, detected via `~/.gemini` | `hooks` in `.gemini/settings.json` | no | Lessons are appended to the prompt (`BeforeAgent`). For the tools, `init --editor gemini` prints the `gemini mcp add` line |
|
|
315
319
|
| **Cline** | yes, detected via VS Code | `.vscode/mcp.json` | no | Shares the config with Copilot; restart VS Code |
|
|
316
320
|
| **Continue.dev** | yes, detected via `.continue/` | `.continue/config.json` | no | Uses the `modelContextProtocolServers` key |
|
|
317
321
|
| **Zed** | yes, detected via `.zed/` | `.zed/settings.json` | no | Uses the `context_servers` key |
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import{createHmac as oe}from"node:crypto";import{ckgSlug as k,extractProblemConcept as ne,ckgUpsertNode as J,ckgUpdateEdge as
|
|
2
|
-
`);const l=[{name:"InfraAgent",domains:["infra","k8s","docker","server","wireguard","helm"]},{name:"AuthAgent",domains:["auth","jwt","keycloak","oauth","oidc","token"]},{name:"DeployAgent",domains:["deploy","ci","pipeline","rsync","release"]},{name:"DatabaseAgent",domains:["db","gorm","migration","postgres","clickhouse","redis"]},{name:"DebugAgent",domains:["debug","panic","race","nil","fix","error"]},{name:"APIAgent",domains:["api","http","grpc","rest","fiber","web"]}],u=i.split(":")[0]??"",
|
|
3
|
-
`);const
|
|
4
|
-
`)}case"cls_ingest":{const{instance_id:_,source:i,payload:n}=N,t=await I(_),e=new Date().toISOString(),l="cachly:cls:events";if(i==="git_commit"){const u=String(n.message??""),
|
|
5
|
-
`)}if(i==="ci_outcome"){const u=String(n.status??""),
|
|
6
|
-
`)}if(i==="ide_diagnostic"){const u=String(n.error??""),
|
|
1
|
+
import{createHmac as oe}from"node:crypto";import{ckgSlug as k,extractProblemConcept as ne,ckgUpsertNode as J,ckgUpdateEdge as M,ckgUpsertPersonNode as ie,ckgUpsertFileNode as ae,ckgRecordCollaboration as ce}from"../ckg.js";import{safeJsonParse as D,normalizeGitPath as re}from"../utils.js";import{buildClsPostCommitHook as le}from"../cls-hook.js";import{installBrainWatchHook as ue}from"../brain-watch-hook.js";import{keywordSearch as de,wortindexEntwerten as fe}from"../search.js";import{buildFirstContactReport as Z,suggestRecallQueries as he}from"../first-contact.js";import{classifyCommit as me,extractDomain as pe}from"../commit-art.js";import{VEKTOR_NACHTRAG as ge}from"../bedeutung.js";let _e=null,we=null,U=0;const ye=10,ee=[];function $e(){return U<ye?(U++,Promise.resolve()):new Promise(B=>ee.push(B))}function be(){const B=ee.shift();B?B():U--}const Re=new Set(["madc_deliberate","cls_ingest","cls_install_hooks","fedbrain_contribute","fedbrain_search","fedbrain_confirm","fedbrain_status","brain_federate","crystal_view","compact_recover","brain_from_git","brain_from_ci","brain_predict_failures","brain_contribute_signal","brain_import_meta","brain_watch"]);async function Ae(B,N,I,K){switch(B){case"madc_deliberate":{const{instance_id:_,topic:i}=N,n=await I(_),e=(await n.lrange(`cachly:lessons:${i}`,0,-1)).map(g=>{try{return JSON.parse(g)}catch{return null}}).filter(Boolean);if(e.length<2)return[`\u{1F5F3}\uFE0F **MADC: "${i}"**`,"",`Not enough history for deliberation (need \u2265 2 entries, found ${e.length}).`,"","Call `learn_from_attempts` with conflicting outcomes to trigger deliberation."].join(`
|
|
2
|
+
`);const l=[{name:"InfraAgent",domains:["infra","k8s","docker","server","wireguard","helm"]},{name:"AuthAgent",domains:["auth","jwt","keycloak","oauth","oidc","token"]},{name:"DeployAgent",domains:["deploy","ci","pipeline","rsync","release"]},{name:"DatabaseAgent",domains:["db","gorm","migration","postgres","clickhouse","redis"]},{name:"DebugAgent",domains:["debug","panic","race","nil","fix","error"]},{name:"APIAgent",domains:["api","http","grpc","rest","fiber","web"]}],u=i.split(":")[0]??"",a=l.filter(g=>g.domains.some(S=>u===S||i.includes(S))),o=a.length>0?a:l,d=new Map;for(const g of o){let S=0;for(const $ of g.domains){const x=[],v=n.scanStream({match:`cachly:ckg:node:${$}*`,count:50});await new Promise((L,P)=>{v.on("data",R=>x.push(...R)),v.on("end",L),v.on("error",P)}),S+=x.length}d.set(g.name,S)}const h=e.filter(g=>g.outcome==="success"||g.outcome==="partial"),s=e.filter(g=>g.outcome==="failure");if(s.length===0)return[`\u{1F5F3}\uFE0F **MADC: "${i}"**`,"",`No contradictions found \u2014 all ${h.length} entries have non-failure outcomes.`,"",`Use \`ckg_inspect(concept="${k(i)}")\` to explore the confidence graph.`].join(`
|
|
3
|
+
`);const c=[];for(const g of o){const S=d.get(g.name)??0;let $,x;S<2?($="abstain",x="insufficient domain coverage"):h.length>=s.length*2?($="success",x=`${h.length}/${e.length} entries confirm success`):s.length>=h.length*2?($="failure",x=`${s.length}/${e.length} entries confirm failure`):($="abstain",x=`contested (${h.length} success vs ${s.length} failure)`),c.push({agent:g.name,vote:$,coverage:S,reason:x})}const r=c.filter(g=>g.vote==="success").length,f=c.filter(g=>g.vote==="failure").length,m=c.filter(g=>g.vote==="abstain").length;let p,w;r>0&&f===0?(p="unanimous_success",w=`\u2705 **Unanimous: SUCCESS** \u2014 ${r} agent(s) confirm, ${m} abstain`):f>0&&r===0?(p="unanimous_failure",w=`\u274C **Unanimous: FAILURE** \u2014 ${f} agent(s) confirm, ${m} abstain`):(p="contested",w=`\u26A0\uFE0F **CONTESTED** \u2014 ${r} success votes, ${f} failure votes, ${m} abstain`);const y=k(`resolution:${i}`),j={id:y,domain:"resolution",type:"resolution",count:1,ts:new Date().toISOString(),resolution:p,topic:i,votes:{success:r,failure:f,abstain:m}};if(await n.set(`cachly:ckg:node:${y}`,JSON.stringify(j)),p==="contested")await M(n,k(i),"contradicts",y,!1);else{if(((p==="unanimous_success"?"failure":"success")==="failure"?s:h).length>0){const $=await n.smembers(`cachly:ckg:idx:from:${k(i)}`);for(const x of $){const v=await n.get(x);if(v)try{const L=JSON.parse(v);L.edgeType==="fixes"&&L.confidence>.15&&p==="unanimous_failure"&&(L.confidence=.1,L.last_updated=new Date().toISOString(),await n.set(x,JSON.stringify(L)))}catch{}}}await n.del(`cachly:ckg:conflict:${k(i)}`)}const C=[`\u{1F5F3}\uFE0F **MADC Deliberation: "${i}"**`,"",`\u{1F4CA} Evidence: ${h.length} success/partial vs ${s.length} failure entries (${e.length} total)`,"",`**Voting agents (${o.length}):**`,...c.map(g=>{const S=g.vote==="success"?"\u2705":g.vote==="failure"?"\u274C":"\u2B1C",$="\u2593".repeat(Math.min(g.coverage,5))+"\u2591".repeat(Math.max(0,5-g.coverage));return` ${S} **${g.agent}** [${$}] ${g.coverage} CKG edges \u2014 ${g.reason}`}),"",w,""];return p==="unanimous_success"?C.push(`\u{1F527} Failure entries superseded \u2014 store confirmed lesson: \`learn_from_attempts(topic="${i}", outcome="success", ...)\``):p==="unanimous_failure"?C.push(`\u{1F6AB} Success claims unconfirmed \u2014 re-verify: \`recall_best_solution(topic="${i}")\``):C.push(`\u26A0\uFE0F Contested \u2014 run \`causal_trace\` before acting. Explore: \`ckg_inspect(concept="${k(i)}")\``),C.push("",`\u{1F4DD} Resolution node: \`cachly:ckg:node:${y}\``),C.join(`
|
|
4
|
+
`)}case"cls_ingest":{const{instance_id:_,source:i,payload:n}=N,t=await I(_),e=new Date().toISOString(),l="cachly:cls:events";if(i==="git_commit"){const u=String(n.message??""),a=String(n.sha??""),o=Array.isArray(n.files)?n.files:[],d=/^fix/i.test(u)?"fix":/^feat/i.test(u)?"feat":/^refactor/i.test(u)?"refactor":/^test/i.test(u)?"test":"commit",h=`${d}:${k(u.slice(0,60))}`,s=k(h);await J(t,s,d,"commit");for(const f of o.slice(0,10)){const m=f.includes("auth")?"auth":f.includes("api")?"api":f.includes("infra")?"infra":f.includes("web")?"web":"code",p=k(`file:${m}`);await J(t,p,"file",m),await M(t,s,"co-occurs",p,!0)}const c={topic:h,outcome:"success",what_worked:u,what_failed:"",context:`CLS/git: sha=${a}`,severity:"minor",file_paths:o.slice(0,10),commands:a?[`git show ${a}`]:[],tags:["cls","git"],depends_on:[],recall_count:0,ts:e,verified_at:e,confidence:.6,audit_trail:[{ts:e,action:"cls_git_commit"}],version:3};return await t.rpush(`cachly:lessons:${h}`,JSON.stringify(c)),await t.get(`cachly:lesson:best:${h}`)||await t.set(`cachly:lesson:best:${h}`,JSON.stringify(c)),await t.rpush(l,JSON.stringify({source:i,payload:{message:u,sha:a},ts:e})),await t.ltrim(l,-200,-1),["\u{1F4E8} **CLS Ingested: git_commit**","",`Commit \`${a.slice(0,8)||"?"}\`: ${u.slice(0,80)}`,`Concept: \`${s}\` (${d}) \xB7 Files: ${o.length}`,"",`\u{1F578}\uFE0F CKG: \`${s}\` + ${o.length} file edges \xB7 Lesson: \`${h}\``,`\u{1F4A1} Inspect: \`ckg_inspect(concept="${d}")\``].join(`
|
|
5
|
+
`)}if(i==="ci_outcome"){const u=String(n.status??""),a=String(n.prev_status??""),o=String(n.job??"unknown"),d=String(n.context??""),h=["failure","red","error"].includes(a)&&["success","green","passed"].includes(u),s=["success","green","passed"].includes(a)&&["failure","red","error"].includes(u),c=`ci:${k(o)}`,r=k(c);if(await J(t,r,"ci","job"),h){const m=k(`problem:${k(o)}`);await J(t,m,"problem","ci-failure"),await M(t,r,"fixes",m,!0);const p={topic:c,outcome:"success",what_worked:`CI job "${o}" went ${a} \u2192 ${u}`,what_failed:`Job "${o}" was failing`,context:`CLS/ci: ${d}`,severity:"major",file_paths:[],commands:[],tags:["cls","ci"],depends_on:[],recall_count:0,ts:e,verified_at:e,confidence:.75,audit_trail:[{ts:e,action:"cls_ci_fixed"}],version:3};await t.rpush(`cachly:lessons:${c}`,JSON.stringify(p)),await t.set(`cachly:lesson:best:${c}`,JSON.stringify(p))}else if(s){const m=k(`cause:${k(o)}`);await J(t,m,"cause","ci-break"),await M(t,r,"causes",m,!1)}return await t.rpush(l,JSON.stringify({source:i,payload:{status:u,prev_status:a,job:o},ts:e})),await t.ltrim(l,-200,-1),["\u{1F4E8} **CLS Ingested: ci_outcome**","",`${h?"\u2705 Fixed":s?"\u{1F534} Broken":"\u{1F4CA} Recorded"}: \`${o}\` \u2014 ${a||"?"} \u2192 ${u}`,h?"\u{1F527} CKG `fixes` edge added (75% confidence)":s?"\u26A1 CKG `causes` edge added":"\u{1F4CA} State recorded",`\u{1F4A1} Lesson: \`${c}\` | Predict: \`brain_predict(context="${o}")\``].join(`
|
|
6
|
+
`)}if(i==="ide_diagnostic"){const u=String(n.error??""),a=String(n.fix??""),o=String(n.file??""),d=ne(u)??"unknown-error",h=`debug:${k(d)}`,s=k(h),c=k(`problem:${d}`);await J(t,s,"debug","diagnostic"),await J(t,c,"problem","compiler-error"),await M(t,s,"fixes",c,!0);const r={topic:h,outcome:"success",what_worked:a,what_failed:u,context:`CLS/ide: ${o}`,severity:"minor",file_paths:o?[o]:[],commands:[],tags:["cls","ide-diagnostic"],depends_on:[],recall_count:0,ts:e,verified_at:e,confidence:.65,audit_trail:[{ts:e,action:"cls_ide_diagnostic"}],version:3};return await t.rpush(`cachly:lessons:${h}`,JSON.stringify(r)),await t.get(`cachly:lesson:best:${h}`)||await t.set(`cachly:lesson:best:${h}`,JSON.stringify(r)),await t.rpush(l,JSON.stringify({source:i,payload:{error:u.slice(0,60),fix:a.slice(0,60),file:o},ts:e})),await t.ltrim(l,-200,-1),["\u{1F4E8} **CLS Ingested: ide_diagnostic**","",`Error: \`${u.slice(0,80)}\``,`Fix: ${a.slice(0,100)}`,o?`File: \`${o}\``:"","",`\u{1F578}\uFE0F CKG: \`${s}\` \u2192 fixes \u2192 \`${c}\` | Lesson: \`${h}\``].filter(m=>m!=="").join(`
|
|
7
7
|
`)}return`\u274C Unknown CLS source: "${i}". Valid: git_commit, ci_outcome, ide_diagnostic`}case"cls_install_hooks":{const{instance_id:_,repo_path:i=".",hooks:n=["git","ci"]}=N,t=Array.isArray(n)?n:["git","ci"],e=[`\u{1F50C} **CLS Hook Installation Guide**
|
|
8
8
|
`];if(t.includes("git")){const l=le(_);e.push("### Git post-commit hook"),e.push("**Quick install (run once per repo):**"),e.push("```sh"),e.push(`touch ${i}/.git/hooks/post-commit`),e.push(`grep -q 'cachly CLS' ${i}/.git/hooks/post-commit || cat >> ${i}/.git/hooks/post-commit << 'HOOK'`),e.push(l),e.push("HOOK"),e.push(`chmod +x ${i}/.git/hooks/post-commit`),e.push("```"),e.push("After install: every `git commit` automatically updates your brain's CKG."),e.push("")}return t.includes("ci")&&(e.push("### GitHub Actions CI outcome hook"),e.push("**Add at the end of each job** (after build/test steps):"),e.push("```yaml"),e.push("- name: cachly CLS \u2014 record CI outcome"),e.push(" if: always()"),e.push(" run: |"),e.push(' node -e "'),e.push(" const r=require('https');"),e.push(` const d=JSON.stringify({instance_id:'${_}',source:'ci_outcome',payload:{`),e.push(" status:'${{ job.status }}',prev_status:'unknown',job:'${{ github.job }}',"),e.push(" context:'github-actions run ${{ github.run_number }}'}});"),e.push(" r.request({hostname:'api.cachly.dev',path:'/api/v1/cls/ingest',method:'POST',"),e.push(" headers:{'Content-Type':'application/json','Authorization':'Bearer $CACHLY_JWT',"),e.push(" 'Content-Length':d.length}},()=>{}).end(d);"),e.push(' " 2>/dev/null || true'),e.push(" env:"),e.push(" CACHLY_JWT: ${{ secrets.CACHLY_JWT }}"),e.push("```"),e.push("")),e.push('\u{1F4A1} Once installed: `brain_search(query="cls")` to verify events are arriving.'),e.push('\u{1F4CA} Monitor CKG growth: `ckg_inspect(concept="ci")` or `ckg_inspect(concept="fix")`'),e.join(`
|
|
9
|
-
`)}case"fedbrain_contribute":{const{instance_id:_,lesson_key:i,visibility:n="public"}=N,t=await I(_),e=await t.get(`cachly:lesson:best:${i}`);if(!e)return`\u274C Lesson \`${i}\` not found. Store it first with \`learn_from_attempts\`.`;const l=
|
|
10
|
-
`)}case"fedbrain_search":{const{instance_id:_,query:i,context_hints:n=[],limit:t=10}=N,e=await I(_),l=await e.smembers("cachly:fedbrain:contributed"),u=new Map;for(const
|
|
11
|
-
`);const h=
|
|
12
|
-
`];for(const
|
|
9
|
+
`)}case"fedbrain_contribute":{const{instance_id:_,lesson_key:i,visibility:n="public"}=N,t=await I(_),e=await t.get(`cachly:lesson:best:${i}`);if(!e)return`\u274C Lesson \`${i}\` not found. Store it first with \`learn_from_attempts\`.`;const l=D(e,null);if(!l)return`\u274C Lesson \`${i}\` data is corrupted. Re-store with \`learn_from_attempts\`.`;const u=[l.topic.split(":")[0],...l.tags??[]].filter(Boolean),a=[...new Set(u)].sort().join(","),o=`${l.topic}:${l.outcome}:${l.what_worked}`,d=oe("sha256",`cachly-fedbrain:${_}`).update(o).digest("hex").slice(0,16),h={cert_id:d,lesson_key:i,visibility:n,domain_fingerprint:a,contributed_at:new Date().toISOString(),confirm_count:0,trust_score:l.outcome==="success"?.85:.5};await t.set(`cachly:fedbrain:cert:${d}`,JSON.stringify(h)),await t.sadd("cachly:fedbrain:contributed",d);let s;try{await K("/api/v1/syndication/contribute",{method:"POST",body:JSON.stringify({topic:l.topic,outcome:l.outcome,what_worked:l.what_worked,what_failed:l.what_failed??"",severity:l.severity??"major",cert_id:d,domain_fingerprint:a,visibility:n})}),s="\u2705 Contributed to global commons"}catch{s="\u{1F4E6} Stored locally (commons API unavailable \u2014 will sync when online)"}return[`\u{1F310} **FedBrain Contribute: "${i}"**`,"",`\u{1F4DC} Certificate: \`${d}\``,`\u{1F3F7}\uFE0F Domain fingerprint: ${u.slice(0,6).map(c=>`\`${c}\``).join(", ")}`,`\u{1F512} Visibility: ${n}`,"",s,"","\u{1F4A1} At 10 independent confirms \u2192 \u{1F3C6} Gold Standard",`\u{1F50D} Search: \`fedbrain_search(query="${l.topic.split(":").slice(-1)[0]}")\``].join(`
|
|
10
|
+
`)}case"fedbrain_search":{const{instance_id:_,query:i,context_hints:n=[],limit:t=10}=N,e=await I(_),l=await e.smembers("cachly:fedbrain:contributed"),u=new Map;for(const c of l.slice(0,30)){const r=await e.get(`cachly:fedbrain:cert:${c}`);if(r)try{const f=JSON.parse(r);for(const m of(f.domain_fingerprint??"").split(",").filter(Boolean))u.set(m,(u.get(m)??0)+1)}catch{}}for(const c of Array.isArray(n)?n:[])u.set(c.toLowerCase(),(u.get(c.toLowerCase())??0)+2);let a=[],o=!1;try{const c=new URLSearchParams({q:i,limit:String(Math.min(t*2,50))});a=(await K(`/api/v1/syndication/search?${c}`)).results??[]}catch{o=!0;const c=[],r=e.scanStream({match:"cachly:lesson:best:*",count:200});await new Promise((f,m)=>{r.on("data",p=>c.push(...p)),r.on("end",f),r.on("error",m)});for(const f of c.slice(0,60)){const m=await e.get(f);if(m)try{const p=JSON.parse(m),w=`${p.topic} ${p.what_worked??""} ${p.what_failed??""}`.toLowerCase();i.toLowerCase().split(/\s+/).some(y=>y.length>2&&w.includes(y))&&a.push({id:f.split(":").pop()??f,topic:p.topic,category:p.topic.split(":")[0],outcome:p.outcome,what_worked:p.what_worked??"",severity:p.severity??"major",confirm_count:0,created_at:p.ts??new Date().toISOString()})}catch{}}}const d=o?" \u2014 \u26A0\uFE0F Commons unreachable, local fallback (this machine only, not confirmed by the network)":"";if(a.length===0)return[`\u{1F310} **FedBrain Search: "${i}"**${d}`,"",'No results. Contribute: `fedbrain_contribute(lesson_key="fix:...")`'].join(`
|
|
11
|
+
`);const h=a.map(c=>{const r=(c.domain_fingerprint??c.category??"").split(",").filter(Boolean),f=r.reduce((y,j)=>y+(u.get(j)??0),0),m=u.size>0?f/Math.max(1,u.size+r.length):0,p=Math.min(1,c.confirm_count/10),w=m*.4+p*.4+(c.outcome==="success"?.2:0);return{...c,weightedScore:w,isGoldStandard:!o&&c.confirm_count>=10}}).sort((c,r)=>r.weightedScore-c.weightedScore).slice(0,t),s=[`\u{1F310} **FedBrain Search: "${i}"** \u2014 ${h.length} result${h.length!==1?"s":""} (context-weighted)${d}
|
|
12
|
+
`];for(const c of h){const r=c.outcome==="success"?"\u2705":c.outcome==="failure"?"\u274C":"\u26A0\uFE0F",f=c.isGoldStandard?" \u{1F3C6} _Gold Standard_":!o&&c.confirm_count>=3?` \u2713${c.confirm_count}`:"",m=Math.round(c.weightedScore*100);s.push(`${r}${f} **\`${c.topic}\`** [ctx: ${m}%]`),c.what_worked&&s.push(` \u2705 ${c.what_worked.slice(0,150)}`),c.what_failed&&s.push(` \u274C ${c.what_failed.slice(0,80)}`),s.push(` _${c.confirm_count} confirm${c.confirm_count!==1?"s":""} | id: \`${c.id}\`_`,"")}if(u.size>0){const c=[...u.entries()].sort((r,f)=>f[1]-r[1]).slice(0,5).map(([r,f])=>`\`${r}\`(${f})`).join(", ");s.push(`\u{1F3AF} Your context: ${c}`)}return s.push('\u{1F4A1} Confirm a result: `fedbrain_confirm(id="<id>", topic="<topic>", outcome="worked")`'),s.join(`
|
|
13
13
|
`)}case"fedbrain_confirm":{const{instance_id:_,id:i,topic:n,outcome:t}=N;if(!i)return["\u274C **FedBrain Confirm** needs the lesson `id` from `fedbrain_search` results.",'Run `fedbrain_search(query="...")`, copy the id shown next to a result,','then: `fedbrain_confirm(id="<id>", topic="<topic>", outcome="worked")`.'].join(`
|
|
14
|
-
`);const e=await I(_),l=new Date().toISOString(),u=JSON.stringify({id:i,topic:n,outcome:t,ts:l});await e.rpush("cachly:fedbrain:confirmations",u),await e.ltrim("cachly:fedbrain:confirmations",-200,-1);const
|
|
15
|
-
`)}case"fedbrain_status":{const{instance_id:_}=N,i=await I(_),n=await i.smembers("cachly:fedbrain:contributed"),t=await i.lrange("cachly:fedbrain:confirmations",-10,-1),e=await i.llen("cachly:fedbrain:pending_confirms"),l=t.map(o=>{try{return JSON.parse(o)}catch{return null}}).filter(Boolean),u=[];for(const o of n.slice(0,15)){const d=await i.get(`cachly:fedbrain:cert:${o}`);if(d)try{const h=JSON.parse(d);u.push({cert_id:h.cert_id,lesson_key:h.lesson_key,confirm_count:h.confirm_count??0,trust_score:h.trust_score??.5,isGold:(h.confirm_count??0)>=10})}catch{}}const
|
|
16
|
-
`,`### \u{1F4E4} Contributed Lessons: ${n.length}`];if(u.length>0)for(const o of u){const d=o.isGold?" \u{1F3C6} Gold Standard":"",h="\u2588".repeat(Math.min(10,o.confirm_count))+"\u2591".repeat(Math.max(0,10-o.confirm_count));
|
|
17
|
-
`)}case"brain_federate":{const{instance_id:_,source:i,domain:n,min_confidence:t=.6,dry_run:e=!1}=N;if(_===i)return"\u274C Source and destination cannot be the same brain.";const l=await I(_),u=await I(i),
|
|
18
|
-
`);let h=0,s=0,
|
|
14
|
+
`);const e=await I(_),l=new Date().toISOString(),u=JSON.stringify({id:i,topic:n,outcome:t,ts:l});await e.rpush("cachly:fedbrain:confirmations",u),await e.ltrim("cachly:fedbrain:confirmations",-200,-1);const a=t==="worked",o=t==="partially_worked";n&&await M(e,k(n),"fixes",k(`syndicated:${n}`),a,o);let d;try{await K(`/api/v1/syndication/${encodeURIComponent(i)}/confirm`,{method:"POST"}),d="\u2705 Confirmation propagated to global commons"}catch{await e.rpush("cachly:fedbrain:pending_confirms",u),await e.ltrim("cachly:fedbrain:pending_confirms",-50,-1),d="\u{1F4E6} Queued locally (API unavailable \u2014 will propagate on next online session)"}return[`${a?"\u2705":o?"\u26A0\uFE0F":"\u274C"} **FedBrain Confirm: "${n??i}"** \u2192 ${t}`,"",d,"",n?`\u{1F578}\uFE0F CKG confidence ${a||o?"boosted":"reduced"} for \`${k(n)}\``:"\u{1F578}\uFE0F Local CKG unchanged (pass `topic` to also update your own confidence graph)","\u{1F4A1} Your confirmation helps other brains worldwide.",'\u{1F4CA} Status: `fedbrain_status(instance_id="...")`'].join(`
|
|
15
|
+
`)}case"fedbrain_status":{const{instance_id:_}=N,i=await I(_),n=await i.smembers("cachly:fedbrain:contributed"),t=await i.lrange("cachly:fedbrain:confirmations",-10,-1),e=await i.llen("cachly:fedbrain:pending_confirms"),l=t.map(o=>{try{return JSON.parse(o)}catch{return null}}).filter(Boolean),u=[];for(const o of n.slice(0,15)){const d=await i.get(`cachly:fedbrain:cert:${o}`);if(d)try{const h=JSON.parse(d);u.push({cert_id:h.cert_id,lesson_key:h.lesson_key,confirm_count:h.confirm_count??0,trust_score:h.trust_score??.5,isGold:(h.confirm_count??0)>=10})}catch{}}const a=[`\u{1F310} **FedBrain Status**
|
|
16
|
+
`,`### \u{1F4E4} Contributed Lessons: ${n.length}`];if(u.length>0)for(const o of u){const d=o.isGold?" \u{1F3C6} Gold Standard":"",h="\u2588".repeat(Math.min(10,o.confirm_count))+"\u2591".repeat(Math.max(0,10-o.confirm_count));a.push(` \`${o.lesson_key}\` [${h}] \xD7${o.confirm_count}${d}`)}else a.push(' _None yet. Contribute with `fedbrain_contribute(lesson_key="fix:...")`_');if(a.push("",`### \u{1F4E5} Recent Confirmations: ${l.length}`),l.length>0)for(const o of l.slice(-5)){const d=o.outcome==="worked"?"\u2705":o.outcome==="partially_worked"?"\u26A0\uFE0F":"\u274C";a.push(` ${d} \`${o.topic}\` \u2014 ${o.outcome} (${new Date(o.ts).toLocaleDateString("de-DE")})`)}else a.push(" _None yet. Confirm syndicated lessons with `fedbrain_confirm`_");return e>0&&a.push("",`\u26A0\uFE0F ${e} confirmation${e!==1?"s":""} pending propagation`),a.push("","---",'**Contribute:** `fedbrain_contribute(lesson_key="fix:...")`','**Search:** `fedbrain_search(query="...")`','**Confirm:** `fedbrain_confirm(id="...", topic="...", outcome="worked")`'),a.join(`
|
|
17
|
+
`)}case"brain_federate":{const{instance_id:_,source:i,domain:n,min_confidence:t=.6,dry_run:e=!1}=N;if(_===i)return"\u274C Source and destination cannot be the same brain.";const l=await I(_),u=await I(i),a=n==="*"?"cachly:ckg:node:*":`cachly:ckg:node:${n}*`,o=[],d=u.scanStream({match:a,count:100});if(await new Promise((w,y)=>{d.on("data",j=>o.push(...j)),d.on("end",w),d.on("error",y)}),o.length===0)return[`\u{1F9E0} **brain_federate: "${n}"**`,"",`No CKG nodes found in source brain for domain \`${n}\`.`,"The source brain may not have knowledge in this area yet.",`Try: \`fedbrain_search(query="${n}")\` to find global commons knowledge instead.`].join(`
|
|
18
|
+
`);let h=0,s=0,c=0,r=0;const f=[];for(const w of o){const y=await u.get(w);if(!y)continue;let j;try{j=JSON.parse(y)}catch{continue}e||await l.set(w,y),h++;const C=await u.smembers(`cachly:ckg:idx:from:${j.id}`);for(const $ of C){const x=await u.get($);if(!x)continue;let v;try{v=JSON.parse(x)}catch{continue}if(v.confidence<t){r++;continue}e||(await l.set($,x),await l.sadd(`cachly:ckg:idx:from:${v.from}`,$),await l.sadd(`cachly:ckg:idx:to:${v.to}`,$)),s++}const g=`cachly:lesson:best:${j.id}`,S=await u.get(g);if(S&&(e||await l.set(g,S),c++,f.length<8))try{const $=JSON.parse(S),x=$.outcome==="success"?"\u2705":$.outcome==="failure"?"\u274C":"\u26A0\uFE0F";f.push(` ${x} \`${$.topic}\` \u2014 ${($.what_worked??"").slice(0,80)}`)}catch{}}if(!e){const w=JSON.stringify({source:i,domain:n,transferred_at:new Date().toISOString(),nodes:h,edges:s,lessons:c});await l.rpush("cachly:fedbrain:federations",w),await l.ltrim("cachly:fedbrain:federations",-50,-1)}const p=[`\u{1F9E0} **brain_federate: "${n}"**${e?" (DRY RUN \u2014 no writes)":""}`,"",`\u{1F4E4} Source: \`${i}\``,`\u{1F4E5} Destination: \`${_}\``,`\u{1F50D} Domain filter: \`${n}\` | min_confidence: ${t}`,"","### Transfer Summary",` \u{1F578}\uFE0F CKG nodes: ${h}`,` \u{1F517} CKG edges: ${s} (${r} skipped, confidence < ${t})`,` \u{1F4DA} Lessons: ${c}`,""];return f.length>0&&(p.push("### Sample lessons transferred:",...f),c>f.length&&p.push(` _... and ${c-f.length} more_`),p.push("")),e?p.push("\u{1F4A1} Run without `dry_run: true` to apply the transfer."):(p.push(`\u2705 Transfer complete. Your brain now has the \`${n}\` knowledge from \`${i}\`.`),p.push(`\u{1F50D} Explore: \`ckg_inspect(concept="${n}")\` | \`recall_best_solution(topic="${n}:...")\``)),p.join(`
|
|
19
19
|
`)}case"crystal_view":{const{instance_id:_,show_raw:i=!1}=N,n=await I(_),t=await n.get("cachly:crystal:latest");if(!t)return["\u{1F48E} **Memory Crystal: not yet created**","","No crystal found. Create one with `memory_crystalize()` to compress your accumulated wisdom.","","\u{1F4A1} Tip: run `memory_crystalize` monthly for best results."].join(`
|
|
20
|
-
`);const e=
|
|
20
|
+
`);const e=D(t,null);if(!e)return"\u274C Memory Crystal data is corrupted. Re-create with `memory_crystalize()`.";const l=Math.floor((Date.now()-new Date(e.ts).getTime())/864e5),u=l<=7?"\u{1F7E2}":l<=30?"\u{1F7E1}":"\u{1F534}",a=[`\u{1F48E} **Memory Crystal: ${e.label}**`,"",`\u{1F4C5} Created: ${new Date(e.ts).toLocaleDateString("de-DE")} (${l}d ago ${u})`,`\u{1F4CA} Compressed from: ${e.created_from}`,`\u{1F5C2}\uFE0F Categories: ${e.categories.slice(0,10).map(d=>`\`${d}\``).join(", ")}${e.categories.length>10?` +${e.categories.length-10} more`:""}`,"",`**\u{1F511} Top patterns (${e.top_patterns.length}):**`];for(const d of e.top_patterns)a.push(` \u2022 **${d.category}** (${d.count}\xD7): ${d.insight.slice(0,110)}`);l>30&&a.push("",`\u26A0\uFE0F Crystal is ${l}d old \u2014 run \`memory_crystalize()\` to refresh it.`),i&&a.push("","```json",JSON.stringify(e,null,2),"```");const o=await n.get("cachly:crystal:team:latest").catch(()=>null);if(o){const d=D(o,null);if(d&&d.patterns?.length){const h=Math.floor((Date.now()-new Date(d.ts).getTime())/864e5);a.push("","---",`\u{1F4A0} **Team Crystal: ${d.label}** _(${h}d ago \xB7 ${d.contributors} contributors)_`,"_Fixes multiple teammates independently converged on \u2014 the team-wide layer:_");for(const s of d.patterns.slice(0,5))a.push(` \u2022 \u{1F9E9} **${s.concept}** \u2014 ${s.author_count} people (${s.authors.map(c=>`@${c}`).join(", ")}): ${s.convergent_fix.slice(0,90)}`)}}return a.push("",'\u{1F4A1} Refresh: `memory_crystalize()` \xB7 `team_crystallize()` | Recover: `compact_recover(instance_id="...")`'),a.join(`
|
|
21
21
|
`)}case"compact_recover":{const{instance_id:_,focus:i=""}=N,n=await I(_),t=[`\u{1F501} **Compact Recovery Briefing**
|
|
22
22
|
`];t.push(`> *Call this first after any context limit hit. Reconstructs where you left off.*
|
|
23
|
-
`);const e=await n.get("cachly:crystal:latest");if(e){const s=
|
|
24
|
-
`)}case"brain_from_git":{const _=Date.now(),{instance_id:i,repo_path:n=".",limit:t=100,branch:e="HEAD",since:l="",incremental:u=!0}=N,
|
|
25
|
-
`)){const b=O.trim();if(b.startsWith("COMMIT|||")){g&&C.push(g);const[,
|
|
23
|
+
`);const e=await n.get("cachly:crystal:latest");if(e){const s=D(e,null);if(s){t.push(`### \u{1F48E} Memory Crystal: ${s.label}`),t.push(`Compressed from ${s.session_count} sessions, ${s.lesson_count} lessons.`);const c=i?s.top_patterns.filter(r=>r.category.toLowerCase().includes(i.toLowerCase())||r.insight.toLowerCase().includes(i.toLowerCase())).slice(0,4):s.top_patterns.slice(0,4);for(const r of c)t.push(` \u2022 **${r.category}**: ${r.insight.slice(0,100)}`);t.push("")}}const l=await n.get("cachly:session:last");if(l){const s=D(l,null);s&&(t.push("### \u{1F550} Last Session"),s.focus&&t.push(`Focus: _${s.focus}_`),s.summary&&t.push(`Summary: ${s.summary.slice(0,300)}`),t.push(""))}const u=await n.get("cachly:session:handoff");if(u){const s=D(u,null);if(s){if(t.push("### \u{1F4CB} Handoff (from last window)"),s.context_summary&&t.push(`Context: ${s.context_summary.slice(0,200)}`),s.remaining_tasks?.length){t.push("Remaining tasks:");for(const c of s.remaining_tasks.slice(0,5))t.push(` \u2022 ${c}`)}s.instructions&&t.push(`\u26A0\uFE0F Instructions: ${s.instructions.slice(0,200)}`),s.blocked_on&&t.push(`\u{1F6A7} Blocked on: ${s.blocked_on}`),t.push("")}}const a=await n.get("cachly:ctx:wip-registry");if(a){const s=D(a,null);s?.content&&(t.push("### \u{1F527} WIP Registry"),t.push(s.content.slice(0,400)),t.push(""))}const o=[],d=n.scanStream({match:"cachly:roadmap:*",count:100});await new Promise((s,c)=>{d.on("data",r=>o.push(...r)),d.on("end",s),d.on("error",c)});const h=[];for(const s of o.slice(0,30)){const c=await n.get(s);if(c)try{const r=JSON.parse(c);(r.status==="in_progress"||r.status==="blocked")&&h.push({title:r.title??s,status:r.status,priority:r.priority})}catch{}}if(h.length>0){t.push("### \u{1F6A7} Open Items");for(const s of h.slice(0,5))t.push(` \u2022 [${s.status}] ${s.title}`);t.push("")}if(i){const s=[],c=n.scanStream({match:"cachly:lesson:best:*",count:200});await new Promise((f,m)=>{c.on("data",p=>s.push(...p)),c.on("end",f),c.on("error",m)});const r=[];for(const f of s){const m=await n.get(f);if(m)try{const p=JSON.parse(m);p.topic.toLowerCase().includes(i.toLowerCase())&&p.what_worked&&r.push({topic:p.topic,what_worked:p.what_worked})}catch{}}if(r.length>0){t.push(`### \u{1F4A1} Relevant Lessons for "${i}"`);for(const f of r.slice(0,4))t.push(` \u2022 **${f.topic}**: ${f.what_worked.slice(0,100)}`);t.push("")}}return t.length<=3&&t.push("_No brain data found. Start accumulating knowledge with `learn_from_attempts` and `session_start`._"),t.push("---","\u{1F9E0} Brain is ready. Continue your work \u2014 full context restored."),t.join(`
|
|
24
|
+
`)}case"brain_from_git":{const _=Date.now(),{instance_id:i,repo_path:n=".",limit:t=100,branch:e="HEAD",since:l="",incremental:u=!0}=N,a=await I(i),{execSync:o}=await import("node:child_process"),{resolve:d}=await import("node:path"),h=d(n),s=Math.min(Number(t)||100,500);await $e();try{try{o("git rev-parse --git-dir",{cwd:h,stdio:"pipe"})}catch{return`\u274C Not a git repository: \`${h}\`. Pass \`repo_path\` pointing to a git checkout.`}const c=`cachly:brain_from_git:last_sha:${Buffer.from(h).toString("base64").slice(0,32)}`;let r="",f=!1;u!==!1&&!l&&(r=await a.get(c)??"",f=!!r);const m=l?`--since="${l}"`:"",w=(f?`${r}..HEAD`:"")||e,y=`git log ${w} ${m} --pretty=format:"COMMIT|||%H|||%s|||%ad|||%an" --date=short --no-merges --name-only -n ${s}`;let j="";try{j=o(y,{cwd:h,encoding:"utf-8",stdio:"pipe"})}catch(O){return`\u274C git log failed: ${O.message}. Check \`repo_path\` and \`branch\`.`}const C=[];let g=null;for(const O of j.split(`
|
|
25
|
+
`)){const b=O.trim();if(b.startsWith("COMMIT|||")){g&&C.push(g);const[,A,G,F,q]=b.split("|||");g={sha:(A??"").trim(),subject:(G??"").trim(),date:(F??"").trim(),author:(q??"").trim(),files:[]}}else if(b&&g){const A=re(b);A&&g.files.push(A)}}if(g&&C.push(g),C.length===0)return f?`\u2705 brain_from_git: Brain is up to date \u2014 no new commits since last run (last SHA: \`${r.slice(0,8)}\`).`:Z({repoDir:h,revRange:w,processed:0,ingested:0,skipped:0,durationMs:Date.now()-_,isIncremental:!1,instanceId:i,categories:[],suggestedQueries:[],emptyReason:`No commits found in \`${h}\` on branch \`${e}\`${l?` since ${l}`:""}.`});const S=new Date().toISOString();let $=0,x=0;const v=new Map,L=new Map,P=[];let R=null;const E=C.length,te=Math.max(1,Math.floor(E/10));let z=0;process.stderr.write(`
|
|
26
26
|
\u{1F9E0} brain_from_git: processing ${E} commits from ${h}...
|
|
27
27
|
`);for(let O=0;O<C.length;O++){const b=C[O];if(O-z>=te&&(process.stderr.write(` \u23F3 Processing ${O}/${E} commits (${$} lessons so far)...
|
|
28
|
-
`),z=O),!b.subject){x++;continue}const{category:
|
|
28
|
+
`),z=O),!b.subject){x++;continue}const{category:A,outcome:G,severity:F}=me(b.subject),q=pe(b.subject),T=`${A}:${q}`;v.set(A,(v.get(A)??0)+1),L.set(F,(L.get(F)??0)+1),P.push(T),(!R||A==="fix"&&!R.topic.startsWith("fix:"))&&(R={topic:T,subject:b.subject});const W=b.files.filter(H=>H.length>0).slice(0,12),Y={topic:T,outcome:G,severity:F,what_worked:b.subject.slice(0,200),what_failed:"",context:`git:${b.sha.slice(0,8)} by ${b.author} on ${b.date}`,author:b.author||void 0,file_paths:W,commands:[`git show ${b.sha.slice(0,8)}`],tags:["brain_from_git",A,"git-history"],visibility:"team",depends_on:[],recall_count:0,ts:S,verified_at:S,confidence:.55,audit_trail:[{ts:S,action:"brain_from_git",sha:b.sha.slice(0,8)}],version:3};await a.get(`cachly:lesson:best:${T}`)||(await a.set(`cachly:lesson:best:${T}`,JSON.stringify(Y),"EX",90*86400),await a.rpush(`cachly:lessons:${T}`,JSON.stringify(Y)),await a.ltrim(`cachly:lessons:${T}`,-100,-1),await a.expire(`cachly:lessons:${T}`,90*86400),await a.sadd(ge,T).catch(()=>{})),await a.rpush("cachly:lessons:brain_from_git:all",JSON.stringify({topic:T,sha:b.sha.slice(0,8),subject:b.subject.slice(0,60)})),await a.ltrim("cachly:lessons:brain_from_git:all",-500,-1),await a.expire("cachly:lessons:brain_from_git:all",90*86400);const Q=k(T);if(await J(a,Q,A,"git-derived"),b.author)try{const H=await ie(a,b.author,A);await M(a,H,"authored",Q,G==="success",G==="partial");for(const se of W.slice(0,8)){const X=await ae(a,se);await M(a,H,"touched",X,!0),await ce(a,X,H)}}catch{}$++}process.stderr.write(` \u2705 brain_from_git complete: ${$}/${E} commits ingested
|
|
29
29
|
|
|
30
|
-
`),$>0&&fe(),C.length>0&&C[0]?.sha&&await
|
|
31
|
-
`)}case"brain_predict_failures":{const{instance_id:_,context:i,top_k:n=5,format:t="detailed"}=N,e=await I(_),l=i.toLowerCase().replace(/[^a-z0-9\s\-_:.]/g," ").split(/\s+/).filter(r=>r.length>2),u=[];for(const r of l.slice(0,8)){const f=[],m=e.scanStream({match:`cachly:ckg:node:*${r}*`,count:50});await new Promise((p,w)=>{m.on("data",y=>f.push(...y)),m.on("end",p),m.on("error",w)});for(const p of f.slice(0,5)){const w=await e.get(p);if(!w)continue;const y=
|
|
30
|
+
`),$>0&&fe(),C.length>0&&C[0]?.sha&&await a.set(c,C[0].sha,"EX",2160*3600),_e={fixes:v.get("fix")??0,features:v.get("feat")??0,refactors:v.get("refactor")??0,total:$};let V=null;if(R&&$>0)try{const O=await de(a,["cachly:lesson:best:*"],R.subject,1);if(O.length>0){const b=D(O[0].content,{});V={query:R.subject.slice(0,80),topic:b.topic??O[0].key.replace("cachly:lesson:best:",""),snippet:(b.what_worked??"").slice(0,120)||R.subject.slice(0,120)}}}catch{}return Z({repoDir:h,revRange:w,processed:C.length,ingested:$,skipped:x,durationMs:Date.now()-_,isIncremental:f,lastSha:r,instanceId:i,categories:[...v.entries()].sort((O,b)=>b[1]-O[1]),severities:[...L.entries()].sort((O,b)=>b[1]-O[1]),proof:V,suggestedQueries:he(P,i)})}finally{be()}}case"brain_from_ci":{const{instance_id:_,outcomes:i}=N,n=await I(_),t=Date.now();let e=0,l=0,u=0;const a=i.length;for(const o of i){const d=String(o.status??""),h=String(o.prev_status??""),s=String(o.job??"unknown"),c=String(o.context??""),r=["failure","red","error"].includes(h)&&["success","green","passed"].includes(d),f=["success","green","passed"].includes(h)&&["failure","red","error"].includes(d),m=`ci:${k(s)}`,p=k(m);if(await J(n,p,"ci","job"),r){const y=k(`problem:${k(s)}`);await J(n,y,"problem","ci-failure"),await M(n,p,"fixes",y,!0);const j={topic:m,outcome:"success",what_worked:`CI job "${s}" went ${h} \u2192 ${d}`,what_failed:`Job "${s}" was failing`,context:`brain_from_ci: ${c}`,severity:"major",file_paths:[],commands:[],tags:["brain_from_ci","ci"],depends_on:[],recall_count:0,ts:t,verified_at:t,confidence:.65,audit_trail:[{ts:t,action:"brain_from_ci_fixed"}],version:3};await n.rpush(`cachly:lessons:${m}`,JSON.stringify(j)),await n.ltrim(`cachly:lessons:${m}`,-100,-1),await n.set(`cachly:lesson:best:${m}`,JSON.stringify(j)),e++}else if(f){const y=k(`cause:${k(s)}`);await J(n,y,"cause","ci-break"),await M(n,p,"causes",y,!1),l++}else u++;const w=`cachly:cls:${_}`;await n.rpush(w,JSON.stringify({source:"ci_outcome",payload:{status:d,prev_status:h,job:s},ts:t})),await n.ltrim(w,-200,-1)}return we={fixes:e,breaks:l,stable:u,total:a},[`\u{1F4E5} **brain_from_ci**: Ingested ${a} outcomes \u2014 ${e} fixes learned, ${l} breaks noted, ${u} stable`,"",e>0?`\u2705 ${e} fix lesson${e!==1?"s":""} written (confidence 0.65) \u2014 CKG \`fixes\` edges added`:"",l>0?`\u{1F534} ${l} break${l!==1?"s":""} noted \u2014 CKG \`causes\` edges added`:"",u>0?`\u{1F4CA} ${u} stable outcome${u!==1?"s":""} recorded`:"","",'\u{1F4A1} Explore: `brain_search(query="ci")` | `brain_predict(context="<job-name>")`'].filter(Boolean).join(`
|
|
31
|
+
`)}case"brain_predict_failures":{const{instance_id:_,context:i,top_k:n=5,format:t="detailed"}=N,e=await I(_),l=i.toLowerCase().replace(/[^a-z0-9\s\-_:.]/g," ").split(/\s+/).filter(r=>r.length>2),u=[];for(const r of l.slice(0,8)){const f=[],m=e.scanStream({match:`cachly:ckg:node:*${r}*`,count:50});await new Promise((p,w)=>{m.on("data",y=>f.push(...y)),m.on("end",p),m.on("error",w)});for(const p of f.slice(0,5)){const w=await e.get(p);if(!w)continue;const y=D(w,null);if(!y)continue;const j=await e.smembers(`cachly:ckg:idx:from:${y.id}`);for(const C of j.slice(0,20)){const g=await e.get(C);if(!g)continue;const S=D(g,null);if(!S||S.edgeType!=="causes"&&S.edgeType!=="degrades_under")continue;const $=await e.smembers(`cachly:ckg:idx:from:${S.to}`);let x;for(const v of $.slice(0,10)){const L=await e.get(v);if(!L)continue;const P=D(L,null);if(P&&P.edgeType==="fixes"){const R=await e.get(`cachly:lesson:best:${P.from}`);if(R){x=D(R,null)?.what_worked?.slice(0,120);break}}}u.push({concept:y.id,failure:S.to.replace(/-/g," "),probability:S.confidence,fix:x,source:"ckg"})}}}const a=[],o=e.scanStream({match:"cachly:lesson:best:*",count:300});await new Promise((r,f)=>{o.on("data",m=>a.push(...m)),o.on("end",r),o.on("error",f)});for(const r of a.slice(0,100)){const f=await e.get(r);if(f)try{const m=JSON.parse(f);if(m.outcome!=="failure"&&m.outcome!=="partial"||!m.what_failed)continue;const p=`${m.topic} ${m.what_failed}`.toLowerCase(),w=l.filter(j=>p.includes(j)).length/Math.max(1,l.length);if(w<.15)continue;const y=m.severity==="critical"?.15:m.severity==="major"?.05:0;u.push({concept:m.topic,failure:m.what_failed.slice(0,80),probability:Math.min(.97,(m.confidence??.5)*w*1.5+y),fix:m.what_worked?.slice(0,120),topic:m.topic,source:"lesson"})}catch{}}if(u.length===0)return[`\u{1F52E} **Failure Prediction: "${i}"**`,"","No known failure patterns found for this context.",'\u{1F4A1} The brain learns from every `learn_from_attempts(outcome="failure")` call.',`\u{1F50D} Try: \`brain_predict(context="${i}")\` for broader predictions.`].join(`
|
|
32
32
|
`);const d=new Set,h=u.filter(r=>{const f=r.failure.slice(0,40);return d.has(f)?!1:(d.add(f),!0)}).sort((r,f)=>f.probability-r.probability).slice(0,Number(n)),s=[`\u{1F52E} **Failure Prediction for: "${i}"**
|
|
33
33
|
`];s.push(`> Pre-deploy failure analysis based on ${u.length} patterns. Ranked by probability.
|
|
34
|
-
`);for(let r=0;r<h.length;r++){const f=h[r],m=Math.round(f.probability*100),p="\u2588".repeat(Math.round(m/10))+"\u2591".repeat(10-Math.round(m/10)),w=m>=70?"\u{1F534}":m>=40?"\u{1F7E1}":"\u{1F7E2}";s.push(`${w} **${r+1}. ${f.failure}**`),s.push(` Probability: ${p} **${m}%** (${f.source==="ckg"?"CKG causal edge":"lesson history"})`),t==="detailed"&&f.fix&&s.push(` \u2705 Pre-loaded fix: _${f.fix}_`),t==="detailed"&&f.topic&&s.push(` \u{1F4DA} Lesson: \`${f.topic}\``),s.push("")}const
|
|
35
|
-
`)}case"brain_contribute_signal":{const{instance_id:_,topic_category:i,outcome:n,confidence:t=.5}=N;if(!i?.trim())throw new Error("topic_category is required");if(!["success","failure","partial"].includes(n))throw new Error("outcome must be success, failure, or partial");const e=t>=.75?"high":t>=.5?"medium":"low";let l="\u{1F4E6} Signal stored locally (commons API unavailable)";try{await K("/api/v1/federation/signals",{method:"POST",body:JSON.stringify({topic_category:i.trim().toLowerCase(),outcome:n,confidence:t})}),l="\u2705 Signal contributed to the global commons (no raw data shared)"}catch{const u=await I(_),
|
|
34
|
+
`);for(let r=0;r<h.length;r++){const f=h[r],m=Math.round(f.probability*100),p="\u2588".repeat(Math.round(m/10))+"\u2591".repeat(10-Math.round(m/10)),w=m>=70?"\u{1F534}":m>=40?"\u{1F7E1}":"\u{1F7E2}";s.push(`${w} **${r+1}. ${f.failure}**`),s.push(` Probability: ${p} **${m}%** (${f.source==="ckg"?"CKG causal edge":"lesson history"})`),t==="detailed"&&f.fix&&s.push(` \u2705 Pre-loaded fix: _${f.fix}_`),t==="detailed"&&f.topic&&s.push(` \u{1F4DA} Lesson: \`${f.topic}\``),s.push("")}const c=h.filter(r=>r.probability>=.6);return c.length>0?s.push(`\u26A0\uFE0F **${c.length} high-risk failure${c.length>1?"s":""} detected** (\u226560% probability). Review fixes before proceeding.`):s.push("\u2705 No high-risk failures detected. Proceed with caution and monitor closely."),s.push("",'\u{1F4A1} After deploy: `learn_from_attempts(topic="deploy:...", outcome="success|failure")` to improve future predictions.'),s.join(`
|
|
35
|
+
`)}case"brain_contribute_signal":{const{instance_id:_,topic_category:i,outcome:n,confidence:t=.5}=N;if(!i?.trim())throw new Error("topic_category is required");if(!["success","failure","partial"].includes(n))throw new Error("outcome must be success, failure, or partial");const e=t>=.75?"high":t>=.5?"medium":"low";let l="\u{1F4E6} Signal stored locally (commons API unavailable)";try{await K("/api/v1/federation/signals",{method:"POST",body:JSON.stringify({topic_category:i.trim().toLowerCase(),outcome:n,confidence:t})}),l="\u2705 Signal contributed to the global commons (no raw data shared)"}catch{const u=await I(_),a=`cachly:fed:outbox:${Date.now()}`;await u.set(a,JSON.stringify({topic_category:i,outcome:n,bucket:e,ts:new Date().toISOString()}),"EX",3600*24*7).catch(()=>{})}return[`\u{1F512} **Brain Contribute Signal: \`${i}\`**`,"",`\u{1F4CA} Outcome: **${n}** \xB7 Confidence bucket: **${e}**`,"\u{1F6E1}\uFE0F Privacy: topic category only \u2014 no lesson text, no org identity","",l,"","\u{1F4A1} When \u2265 k orgs contribute the same pattern, a meta-lesson appears in `brain_import_meta`."].join(`
|
|
36
36
|
`)}case"brain_import_meta":{const{instance_id:_,category:i,limit:n=20}=N;let t=[],e=3;try{const o=new URLSearchParams;i&&o.set("category",i),o.set("limit",String(Math.min(n,200)));const d=await K(`/api/v1/federation/meta?${o.toString()}`);t=d.meta_lessons??[],e=d.k_threshold??3}catch{return"\u274C Could not reach the global commons API. Try again later."}if(t.length===0)return["\u{1F310} **Brain Import Meta-Lessons**","",`No meta-lessons available yet (k-threshold: ${e} signals required).`,"","\u{1F4A1} Contribute signals with `brain_contribute_signal` to help build the commons."].join(`
|
|
37
|
-
`);const l=await I(_);let u=0;for(const o of t){const d=`cachly:lesson:best:meta:${o.topic_category}`;await l.get(d)||(await l.set(d,JSON.stringify({topic:`meta:${o.topic_category}`,outcome:o.dominant_outcome,what_worked:o.contributor_count!=null?`Meta-pattern from ${o.contributor_count} independent orgs`:`Meta-pattern from ${o.signal_count} signals`,what_failed:"",recall_count:0,ts:o.derived_at,state:"meta",avg_confidence:o.avg_confidence,signal_count:o.signal_count,audit_trail:[{ts:new Date().toISOString(),action:"imported_meta"}]})),u++)}const
|
|
37
|
+
`);const l=await I(_);let u=0;for(const o of t){const d=`cachly:lesson:best:meta:${o.topic_category}`;await l.get(d)||(await l.set(d,JSON.stringify({topic:`meta:${o.topic_category}`,outcome:o.dominant_outcome,what_worked:o.contributor_count!=null?`Meta-pattern from ${o.contributor_count} independent orgs`:`Meta-pattern from ${o.signal_count} signals`,what_failed:"",recall_count:0,ts:o.derived_at,state:"meta",avg_confidence:o.avg_confidence,signal_count:o.signal_count,audit_trail:[{ts:new Date().toISOString(),action:"imported_meta"}]})),u++)}const a=[`\u{1F310} **Brain Import Meta-Lessons** (k \u2265 ${e})`,"","| Topic Category | Outcome | Confidence | Signals |","|---|---|---|---|"];for(const o of t.slice(0,15)){const d=(o.avg_confidence*100).toFixed(0)+"%";a.push(`| \`${o.topic_category}\` | ${o.dominant_outcome} | ${d} | ${o.signal_count} |`)}return t.length>15&&a.push(`| _\u2026${t.length-15} more_ | | | |`),a.push("",`\u2705 **${u}** new meta-lessons imported into local Brain.`),u<t.length&&a.push(`_(${t.length-u} already present \u2014 not overwritten)_`),a.join(`
|
|
38
38
|
`)}case"brain_watch":{const{instance_id:_="",project_dir:i=".",api_key:n}=N,{resolve:t}=await import("node:path"),e=t(i),{result:l,hookPath:u}=await ue(e,_,n);return l==="skipped-no-git"?["\u26A0\uFE0F **brain_watch: no git repository found**","",`No \`.git\` directory in \`${e}\`.`,"Pass `project_dir` pointing to a git checkout."].join(`
|
|
39
39
|
`):[`\u{1F9E0} **brain_watch ${{written:"\u2705 Hook installed (new)",upgraded:"\u{1F504} Hook upgraded to latest version",appended:"\u{1F4CE} Hook appended to existing post-commit script",unchanged:"\u2713 Hook already up to date \u2014 nothing changed"}[l]??l}**`,"",`Hook path: \`${u}\``,`Instance: \`${_||"(none \u2014 set CACHLY_BRAIN_INSTANCE_ID or pass instance_id)"}\``,"","Every future commit will automatically teach your Brain.","No manual `brain_from_git` needed \u2014 the hook runs silently in the background.","",'\u{1F4A1} Verify: `git commit --allow-empty -m "test brain_watch"` then `smart_recall(query="test")`'].join(`
|
|
40
|
-
`)}default:return null}}export{
|
|
40
|
+
`)}default:return null}}export{Re as FEDBRAIN_TOOL_NAMES,we as _lastBrainFromCiCounts,_e as _lastBrainFromGitCounts,Ae as handleFedbrainTool};
|
package/dist/src/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{setzeClientKennung as
|
|
2
|
+
import{setzeClientKennung as kt}from"./herkunft.js";import{jwtExpiryMs as Tt,checkJwt as It,handleApiError as Et,diagnoseAuth as xe,planAuthHeal as Ne,readClientCredentialsFromEnv as Rt,buildClientCredentialsBody as Nt,clientCredentialsTokenUrl as Lt}from"./auth.js";import{cachlyUrl as N}from"./cachly-url.js";import{nutzungsSchluessel as Bt}from"./werkzeug-nutzung.js";import{istLieferung as jt,lieferSchluessel as Ht,tokenDerAntwort as Pt,hatTreffer as Ot,trefferSchluessel as Le}from"./geliefert.js";import{notify as Be}from"./notifier.js";import{fileURLToPath as je}from"node:url";import{createRequire as Mt}from"node:module";import{execFile as _e}from"node:child_process";const Dt=process.argv[1]!=null&&(process.argv[1]===je(import.meta.url)||process.argv[1].endsWith("/dist/index.js")||process.argv[1].endsWith("/src/index.ts"));import{Server as He}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Jt}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Yt}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as Pe,ErrorCode as se,ListPromptsRequestSchema as Oe,ListResourceTemplatesRequestSchema as Me,ListResourcesRequestSchema as De,ListToolsRequestSchema as Je,McpError as Q}from"@modelcontextprotocol/sdk/types.js";import{Redis as Ye}from"ioredis";let _=process.env.CACHLY_API_URL??"https://api.cachly.dev",x=et()??"";ce(x);const ls=process.env.CACHLY_EMBED_MODEL??"",D=(()=>{try{const e=Mt(import.meta.url);for(const t of["../../package.json","../package.json"])try{const n=e(t);if(n.name==="@cachly-dev/mcp-server"&&n.version)return n.version}catch{}}catch{}return"0.10.100"})(),Ut=Number(process.env.CACHLY_PROVISION_TIMEOUT_MS??9e4);let j=Ae(process.env.CACHLY_BRAIN_INSTANCE_ID),X=0,ae=null,Ue=!1;async function Wt(){let e=[];try{G.getClientCapabilities()?.roots&&(e=(await G.listRoots(void 0,{timeout:3e3})).roots)}catch{}return sn({wurzeln:e,env:process.env,cwd:process.cwd(),dateiPfad:je})}function me(){return Ue?!/^(0|false|off|no|nein)$/i.test((process.env.CACHLY_STARTWISSEN??"").trim()):!1}function We(e){!e||!me()||en({instanzId:e,verbindung:P,ausGit:t=>Se("brain_from_git",t,P,H),projektOrdner:Wt,einbetten:t=>Ke(t,{geduld:"lang"}),hatEinbettung:Qt,einbettenZweit:t=>Ke(t,{geduld:"lang",modell:Xt}),melde:t=>C("brain_from_git",{...x?{api_key:x}:{},instance_id:e,total:t,auto:"startwissen"}),startvorrat:t=>ke("brain_seed_starter",t,P,H),meldeStartvorrat:t=>C("brain_seed_starter",{...x?{api_key:x}:{},instance_id:e,auto:!0},{seeded_count:t,auto:!0})})}function Fe(){return me()&&rn()}async function Ft(){if(!x)return"";try{const e=await fetch(`${_}/api/v1/instances/auto`,{method:"POST",headers:{Authorization:`Bearer ${x}`,"Content-Type":"application/json"},signal:AbortSignal.timeout(12e3)});if(e.ok){const t=await e.json(),n=t.instance?.id??t.instance_id;if(n)return n}else fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},body:JSON.stringify({event:"auto_provision_failed",status:e.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}catch{fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"auto_provision_failed",status:0,reason:"network_error",version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}return""}async function ze(){if(j)return j;if(!x)return"";if(ae)return ae;const e=Date.now();if(X>0&&e-X<3e4)return"";X=e,ae=(async()=>{try{const t=await fetch(`${_}/api/v1/instances`,{headers:{Authorization:`Bearer ${x}`,Accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(t.ok){const s=(await t.json())?.data??[],o=s.find(i=>i.status==="running")??s.find(i=>i.status==="provisioning");if(o)return j=o.id,X=0,j;const c=await Ft();if(c)return j=c,X=0,nt(c,me(),Fe()),fe(c),We(c),j}}catch{}return""})();try{return await ae}finally{ae=null}}let $e=0;const zt=6e4;let re="";async function ge(e){try{const{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{existsSync:o}=await import("node:fs"),{resolve:c,dirname:i}=await import("node:path"),a=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!a)return;const g=c(a,".claude","mcp.json");let d={};if(o(g))try{d=JSON.parse(await s(g,"utf-8"))}catch{}d.mcpServers??={};const l=d.mcpServers.cachly;if(l)l.env??={},l.env.CACHLY_JWT=e;else{const y={};y.CACHLY_JWT=e,d.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:y}}await n(i(g),{recursive:!0}),await t(g,JSON.stringify(d,null,2),"utf-8");const p=[c(a,".cursor","mcp.json"),c(a,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(p.map(async y=>{if(o(y))try{const w=await s(y,"utf-8"),b=JSON.parse(w),u=b?.mcpServers?.cachly;u?.env&&(u.env.CACHLY_JWT=e,await t(y,JSON.stringify(b,null,2),"utf-8"))}catch{}}))}catch{}}async function fe(e){if(e){tt(e,{apiKey:x});try{const{writeFile:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o}=await import("node:path"),c=process.env.HOME??process.env.USERPROFILE??process.env.APPDATA??"";if(!c)return;const i=[o(c,".claude","mcp.json"),o(c,".cursor","mcp.json"),o(c,".codeium","windsurf","mcp_config.json")];await Promise.allSettled(i.map(async a=>{if(s(a))try{const g=JSON.parse(await n(a,"utf-8")),d=g?.mcpServers?.cachly;d?.env&&(d.env.CACHLY_BRAIN_INSTANCE_ID=e,await t(a,JSON.stringify(g,null,2),"utf-8"))}catch{}}))}catch{}}}async function qt(){try{const e=await fetch(`${_}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`},body:JSON.stringify({name:"cachly-mcp-selfheal",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(!e.ok)return!1;const t=await e.json();return t.key?(x=t.key,ce(t.key),ge(t.key),C("auth_self_healed",{reason:"near_expiry_refresh"}),!0):!1}catch{return!1}}async function Ce(){const e=xe(x),t=Ne(e);if(t==="none")return re="",!0;if(t==="refresh"){const n=Date.now();return n-$e>=zt&&($e=n,await qt())?(re="",!0):(re=e.message,e.usable)}return re=e.message,!1}function ie(e,t){const n=(o,c)=>{try{t?.(o,c)}catch{}},s=o=>{o?n(!1,o.code??o.message):n(!0)};try{process.platform==="win32"?_e("cmd",["/c","start","",e],{windowsHide:!0},s):process.platform==="darwin"?_e("open",[e],s):_e("xdg-open",[e],s)}catch(o){n(!1,o instanceof Error?o.message:"unknown")}}let K=null;async function Kt(){try{const e=await fetch(`${_}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({}),signal:AbortSignal.timeout(8e3)});if(e.ok){const t=await e.json(),n=t.verification_uri||N("/device","ambient-signin"),s=`${n}${n.includes("?")?"&":"?"}code=${encodeURIComponent(t.user_code)}`;return{deviceCode:t.device_code,userCode:t.user_code,verifyUrl:s,pollInterval:(t.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}}catch{}try{const t=await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/auth/device",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"client_id=cachly-cli&scope=openid",signal:AbortSignal.timeout(8e3)});if(!t.ok)return null;const n=await t.json();return{deviceCode:n.device_code,userCode:n.user_code,verifyUrl:n.verification_uri_complete,pollInterval:(n.interval??5)*1e3,deadline:Date.now()+600*1e3,polling:!1}}catch{return null}}async function Gt(e){if(Date.now()>e.deadline)return"expired";const t=async()=>{const s=await fetch(`${_}/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:e.deviceCode}),signal:AbortSignal.timeout(8e3)});return s.ok?s.json():null},n=async()=>(await fetch("https://auth.cachly.dev/realms/cachly/protocol/openid-connect/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`client_id=cachly-cli&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=${e.deviceCode}`,signal:AbortSignal.timeout(8e3)})).json();try{let s=await t().catch(()=>null);if(s||(s=await n().catch(()=>null)),!s)return"pending";if(s.access_token){let o=s.access_token;try{const c=await fetch(`${_}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({name:"cachly-mcp-smithery",scope:"read_write"}),signal:AbortSignal.timeout(8e3)});if(c.ok){const i=await c.json();i.key&&(o=i.key)}}catch{}return x=o,ce(o),K=null,C("device_flow_completed"),ge(o),te(o),X=0,await ze(),j&&fe(j),"done"}return s.error==="slow_down"&&(e.pollInterval=Math.min(e.pollInterval+2e3,15e3)),"pending"}catch{return"pending"}}async function qe(e){if(e.polling)return"pending";e.polling=!0;try{return await Gt(e)}finally{e.polling=!1}}function Vt(e,t=qe,n=o=>K===o,s=Zt){const o=async()=>{if(!n(e))return;let c="pending";try{c=await t(e)}catch{}if(c!=="done"){if(c==="expired"){n(e)&&(K=null);return}n(e)&&s(o,e.pollInterval)}};s(o,e.pollInterval)}function Zt(e,t){const n=setTimeout(e,t);typeof n.unref=="function"&&n.unref()}import{setEmbedJwt as ce,computeEmbedding as Ke,hasEmbedProvider as Qt}from"./embeddings.js";import{ZWEIT_MODELL as Xt}from"./rangfolge-stellschrauben.js";import{tokenize as eo,splitMultiQuery as to,levenshtein as oo,recencyBoost as no,extractTimestamp as so,STOPWORDS as ro,katakanaToRomaji as io,arabicLightStem as ao,expandCrossLingual as co,CROSS_LINGUAL_MAP as lo,ZERO_RESULTS_LOG as po,zeroResultsTotal as uo}from"./search.js";const ee=new Map;function mo(e){return e<=1?200:null}async function P(e){if(!e)throw new Q(se.InvalidRequest,`\u23F3 Your Brain instance is still being set up.
|
|
3
3
|
|
|
4
4
|
This usually resolves in a few seconds \u2014 just call the tool again and it will connect automatically.
|
|
5
5
|
|
|
6
6
|
If it keeps happening:
|
|
7
7
|
\u2022 Run \`list_instances\` to check your instances, or
|
|
8
8
|
\u2022 Set CACHLY_BRAIN_INSTANCE_ID in your MCP config, or
|
|
9
|
-
\u2022 Reach us at support@cachly.dev.`);const t=ee.get(e);return t||
|
|
9
|
+
\u2022 Reach us at support@cachly.dev.`);const t=ee.get(e);return t||Qo(go,e,()=>fo(e))}const go=new Map;async function fo(e){W("verbindung: Instanz abfragen");let t=await H(`/api/v1/instances/${e}`);if(W(`verbindung: Instanz ${t.status}`),t=await Zo(t,()=>H(`/api/v1/instances/${e}`),{fristMs:Ut,melde:i=>W(`verbindung: Instanz ${i.status}`)}),t.status!=="running"){fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...x?{Authorization:`Bearer ${x}`}:{}},body:JSON.stringify({event:"instance_not_reachable",instance_id:e,status:t.status,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{});let i;throw t.status==="provisioning"?i=`\u23F3 Brain instance "${t.name}" is still starting up.
|
|
10
10
|
|
|
11
11
|
First-time provisioning typically takes 1\u20133 minutes. Please retry in a moment \u2014 the instance will be ready soon.`:t.status==="failed"?i=`\u274C Brain instance "${t.name}" failed to start.
|
|
12
12
|
|
|
@@ -18,20 +18,20 @@ Update your payment method at: ${N("/billing","upgrade")}`:t.status==="pending_p
|
|
|
18
18
|
Complete your checkout at: ${N("/instances","upgrade")}`:i=`Brain instance "${t.name}" is not reachable (status: ${t.status}).
|
|
19
19
|
|
|
20
20
|
\u2022 View your instance at: ${N("/instances","instance-error")}
|
|
21
|
-
\u2022 Run \`get_api_status\` for a full diagnostic.`,new Q(se.InvalidRequest,i)}if(!t.host||!t.port)throw new Q(se.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const i=await H(`/api/v1/instances/${e}/connection`);n=i.password??void 0,s=i.tls_enabled!==!1,W("verbindung: Zugangsdaten da")}catch(i){const a=i instanceof Error?i.message:String(i);if(a.includes("401")||a.includes("403")||a.includes("Unauthorized"))throw new Q(se.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Ye({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:
|
|
21
|
+
\u2022 Run \`get_api_status\` for a full diagnostic.`,new Q(se.InvalidRequest,i)}if(!t.host||!t.port)throw new Q(se.InternalError,`Instance "${t.name}" is running but has no host/port \u2014 contact support@cachly.dev.`);let n,s=t.tls_enabled!==!1;try{const i=await H(`/api/v1/instances/${e}/connection`);n=i.password??void 0,s=i.tls_enabled!==!1,W("verbindung: Zugangsdaten da")}catch(i){const a=i instanceof Error?i.message:String(i);if(a.includes("401")||a.includes("403")||a.includes("Unauthorized"))throw new Q(se.InvalidRequest,"API key rejected \u2014 run `cachly setup` to refresh your credentials.")}const o=new Ye({host:t.host,port:t.port,password:n||void 0,commandTimeout:8e3,...s?{tls:{}}:{},lazyConnect:!0,enableReadyCheck:!0,connectTimeout:8e3,retryStrategy:mo,maxRetriesPerRequest:1,keepAlive:15e3}),c=()=>{ee.delete(e),o.disconnect()};o.on("error",c),o.on("end",c);try{await o.connect()}catch(i){o.disconnect();const a=i instanceof Error?i.message:String(i);throw fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json",...x?{Authorization:`Bearer ${x}`}:{}},body:JSON.stringify({event:"redis_connect_failed",instance_id:e,host:t.host,port:t.port,error:a,version:D}),signal:AbortSignal.timeout(3e3)}).catch(()=>{}),new Q(se.InternalError,`Could not reach Brain instance "${t.name}" (${t.host}:${t.port}).
|
|
22
22
|
|
|
23
23
|
\u2022 Check your network connection
|
|
24
24
|
\u2022 Run \`get_api_status\` to verify instance status
|
|
25
|
-
\u2022 Technical detail: ${a}`)}return ee.set(e,o),W("verbindung: Valkey verbunden"),o}async function H(e,t={},n=!1){n||Ne(xe(x))!=="none"&&await Ce(),
|
|
25
|
+
\u2022 Technical detail: ${a}`)}return ee.set(e,o),W("verbindung: Valkey verbunden"),o}async function H(e,t={},n=!1){n||Ne(xe(x))!=="none"&&await Ce(),It(x);const s=Number(process.env.CACHLY_API_TIMEOUT_MS??15e3),o=await fetch(`${_}${e}`,{...t,signal:AbortSignal.timeout(s),headers:{"Content-Type":"application/json",Authorization:`Bearer ${x}`,...t.headers}});if(!o.ok){if(o.status===401&&!n&&($e=0,await Ce()))return H(e,t,!0);const i=(await o.json().catch(()=>({error:o.statusText}))).error??o.statusText;Et(o.status,i)}if(o.status!==204)return o.json()}import{handleBrainTool as ho}from"./handlers/brain.js";import{handleContextTool as yo}from"./handlers/context.js";import{handleInstanceTool as bo}from"./handlers/instances.js";import{handleCacheTool as vo}from"./handlers/cache.js";import{handleTeamTool as wo}from"./handlers/team.js";import{handleRoadmapTool as xo}from"./handlers/roadmap.js";import{handleAdvancedTool as _o}from"./handlers/advanced.js";import{handleSyndicateTool as $o}from"./handlers/syndicate.js";import{handleFedbrainTool as Se,_lastBrainFromGitCounts as he}from"./handlers/fedbrain.js";import{extractFirstRecallProof as Co,renderFirstRecallProof as So}from"./first-recall-proof.js";import{installClsPostCommitHook as Ge,CLS_HOOK_VERSION as Ve}from"./cls-hook.js";import{installAmbientHooks as Ze,installCursorHooks as Ao,installCopilotHooks as ko,installCodexHooks as To,installGeminiHooks as Io,AMBIENT_HOOK_VERSION as Qe,COPILOT_HOOKS_DATEI as Eo,CODEX_HOOKS_DATEI as Ro,GEMINI_SETTINGS_DATEI as No}from"./ambient-hooks.js";import{hookHauptlauf as Lo,auffrischenHauptlauf as Bo}from"./ambient-hook.js";import{rahmeAntwort as jo}from"./antwort-rahmen.js";import{appendLedgerEntry as Ho,readLedger as Xe,defaultLedgerPath as Po,reportLedgerEntry as Oo}from"./ambient-ledger.js";import{resolveApiKey as et,saveApiKey as te,saveInstanceId as tt,readSavedApiKey as Mo}from"./credentials.js";import{KEYCLOAK_BASIS as ot,istTestSchluessel as Do,waehleTestSchluessel as Jo,starteKeycloakAnmeldung as Yo,warteAufKeycloakAnmeldung as Uo,uebernimm as Wo,brainImKonto as Fo,erfolgsText as zo,fehlerText as qo,ersetzeSchluessel as Ko}from"./uebernahme.js";import{holeSofortTest as Go}from"./sofort-test.js";import{sichereZugang as Vo,echterWert as Ae}from"./zugang.js";import{zeitpunkt as W}from"./zeitmessung.js";import{warteAufLaufendeInstanz as Zo,gemeinsamerAufbau as Qo}from"./instanz-warten.js";import{merkeNeuesBrain as nt,startetLautLetztemBlick as Xo}from"./leeres-brain.js";import{starteStartwissen as en,startwissenGestartet as tn,beanspruchStartwissen as on,holeStartwissenHinweis as nn,waehleProjektOrdner as sn,startvorratErlaubt as rn}from"./startwissen.js";import{eigeneFassung as an,pruefeNeueFassung as cn,holeNeueFassungHinweis as ln}from"./neue-fassung.js";import{beiStdinEnde as dn}from"./stdin-ende.js";import{merkeWerkzeugAufruf as pn,starteBrandWachhund as un}from"./brand-wachhund.js";import{sichtbareWerkzeuge as mn,VERTEILER as st}from"./werkzeug-auswahl.js";import{buildLessonsMarkdown as gn,buildLessonsJsonl as fn,vonRohLektion as hn}from"./brain-export.js";import{detectEditor as yn}from"./editor.js";import{milestoneSent as rt,markMilestoneSent as it}from"./funnel-milestones.js";import{kostprobeUebrig as bn,kostprobeVerbrauchen as vn,kostprobeHinweis as wn,schrankeNachKostproben as xn}from"./kostprobe.js";import{netBalance as _n}from"./ambient-recall.js";import{handleShareTool as ke}from"./handlers/share.js";import{handleVizTool as $n}from"./handlers/viz.js";import{commitArt as Cn,istRueckbau as Sn,zaehleLektionen as An}from"./commit-art.js";import{TOOLS as le}from"./tools.js";let at=!1,ye=!1;function ct(){return yn()}function kn(e){if(!e)return null;const t=e.match(/\*\*💡\s+([^*]+)\*\*/),n=e.match(/^>\s+(.+)$/m);if(!t||!n)return null;const s=t[1].trim(),o=n[1].trim();return!s||!o?null:{topic:s,what:o}}function Tn(e){try{const t=e.split(".");if(t.length!==3)return;const n=JSON.parse(Buffer.from(t[1],"base64url").toString("utf-8"));if(!n.sub)return;let s=2166136261;for(let o=0;o<n.sub.length;o++)s^=n.sub.charCodeAt(o),s=s*16777619>>>0;return s.toString(16).padStart(8,"0")+n.sub.length.toString(16).padStart(4,"0")}catch{return}}function C(e,t,n){if(process.env.CACHLY_NO_TELEMETRY==="1")return;const s=x?Tn(x):void 0;fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:e,version:D,editor:ct(),...x?{jwt:x}:{},...s?{user_fingerprint:s}:{},...n?{metrics:n}:{},...t}),signal:AbortSignal.timeout(3e3)}).catch(()=>{})}function In(e,t){return Oo({apiUrl:_,jwt:x,instanceId:e},t)}async function En(e){if(!at&&process.env.CACHLY_NO_TELEMETRY!=="1"){at=!0;try{await fetch(`${_}/api/v1/telemetry/mcp`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({event:"first_call_no_jwt",version:D,editor:ct(),tool:e}),signal:AbortSignal.timeout(3e3)})}catch{}}}const Rn=new Set(["causal_trace","brain_predict","brain_plan","brain_predict_failures","team_learn","team_confirm","team_recall","team_synthesize","team_crystallize","global_learn","global_recall"]),Nn={causal_trace:"Causal root-cause tracing \u2014 follow the failure chain to the real cause, not just the symptom.",brain_predict:"Predictive risk \u2014 your Brain warns you what will break *before* you run it.",brain_plan:"Generative planning \u2014 turn a goal into an ordered, risk-aware plan from your own history.",brain_predict_failures:"Failure prediction \u2014 catch CI/build breakage before it happens.",team_learn:"Team Brain \u2014 one shared memory across your whole team.",team_confirm:"Team Brain \u2014 peer + senior review that raises lesson trust.",team_recall:"Team Brain \u2014 recall everything your teammates have already solved.",team_synthesize:"Team Brain \u2014 synthesize collective knowledge across authors.",team_crystallize:"Team Brain \u2014 compress your team's wisdom into a shareable crystal.",global_learn:"Team Brain \u2014 contribute to your organization's shared memory.",global_recall:"Team Brain \u2014 recall across your entire organization."},lt=N("/billing","upgrade"),dt=new Map;async function Ln(e){const t=dt.get(e);if(t&&t.expiresAt>Date.now())return t.info;try{const s=((await H(`/api/v1/instances/${e}`))?.tier??"free").toLowerCase(),o={tier:s,isFree:s==="free"||s===""};return dt.set(e,{info:o,expiresAt:Date.now()+6e4}),o}catch{return{tier:"unknown",isFree:!1}}}async function Bn(e,t){if(!Rn.has(e)||!t)return null;const{isFree:n}=await Ln(t);if(!n)return null;const s=Nn[e]??"A Premium intelligence feature.";if(bn(e)){const o=vn(e);return{kostprobe:wn(e,o,lt)}}return{sperre:xn(e,s,lt)}}async function jn(e,t){try{await(await P(e)).hincrby(Bt(e),t,1)}catch{}}async function Hn(e,t,n){if(jt(t))try{const s=await P(e),o=Ot(n);await s.incrby(Ht(e),o?Pt(n):0),await s.hincrby(Le(e),"abrufe",1),o&&await s.hincrby(Le(e),"treffer",1)}catch{}}async function Pn(e){const t=await Kt();return t?(K=t,C("device_flow_started",{tool:e}),ie(t.verifyUrl,(n,s)=>{if(n){C("device_browser_opened",{stelle:"tool"});return}C("device_browser_failed",{reason:s??"unknown",stelle:"tool"}),process.stderr.write(`
|
|
26
26
|
cachly: could not open a browser (${s??"unknown"}).
|
|
27
27
|
cachly: open this yourself to finish signing in:
|
|
28
28
|
cachly: ${t.verifyUrl}
|
|
29
29
|
cachly: code ${t.userCode}
|
|
30
30
|
|
|
31
|
-
`)}),
|
|
31
|
+
`)}),Vt(t),["\u{1F9E0} **cachly AI Brain \u2014 the user must sign in once.**","","**Show the following link and code to the user verbatim \u2014 they cannot","continue without them.**","",`\u{1F449} **${t.verifyUrl}**`,"",`Code: **${t.userCode}**`,"","A browser may have opened automatically with the code pre-filled. If it","did not, the link above is the whole step.","","Once signed in, the Brain activates on its own \u2014 no further action, no","restart. The next request arrives brain-powered.","",`\u2728 ${le.length} MCP tools \xB7 GDPR \xB7 EU servers \xB7 free tier, no credit card`].join(`
|
|
32
32
|
`)):["\u{1F9E0} **cachly AI Brain \u2014 Setup required**","","Run the setup wizard once in your terminal:"," ```"," npx @cachly-dev/mcp-server@latest autopilot"," ```","",`Or get your API key at: ${N("/setup-ai","ambient-signin")}`,"","\u2728 Free tier includes: 1 Brain instance, persistent memory, semantic search."].join(`
|
|
33
|
-
`)}async function
|
|
34
|
-
`)}return
|
|
33
|
+
`)}async function On(e){if(!e)return!0;if(tn(e))return!1;try{return await on(await P(e),"sitzungsstart")}catch{return!0}}async function U(e,t){if(!x){if(En(e),K){const r=await qe(K);return r==="done"?U(e,t):r==="expired"?(C("device_flow_failed",{reason:"timeout"}),K=null,"\u231B **Authentication timed out.** Please call any tool again to restart the sign-in flow."):["\u23F3 **Signing you in\u2026**","",`Finish in your browser: **${K.verifyUrl}**`,`Code: **${K.userCode}**`,"","This completes automatically once you sign in \u2014 no need to come back here."].join(`
|
|
34
|
+
`)}return Vo({schluessel:x,konfigurierteInstanz:j,aufrufInstanz:t.instance_id,werkzeugName:e,holeSofortTest:async()=>{W("sofort-test: Anfang");const r=await Go({apiUrl:_,version:D,speichern:()=>{}});return W(`sofort-test: ${r?"Brain angelegt":"kein Test"}`),r&&nt(r.instanzId,me(),Fe()),r},ablagen:{setzeSchluessel:r=>{x=r},setEmbedJwt:ce,saveApiKey:r=>te(r),persistApiKeyToConfig:ge,merkeInstanz:r=>{j=r,X=0},persistInstanceIdToConfig:fe},meldeEreignis:C,werkzeug:()=>U(e,t),anmelden:()=>Pn(e),neuesBrain:We})}if(!t.instance_id){const r=await ze();r&&(t={...t,instance_id:r})}const n=await Bn(e,t.instance_id);let s="";if(n!==null){if("sperre"in n)return C("premium_gate_hit",{tool:e,instance_id:t.instance_id??""}),n.sperre;s=n.kostprobe,C("premium_taste_used",{tool:e,instance_id:t.instance_id??""})}typeof t.instance_id=="string"&&t.instance_id&&jn(t.instance_id,e),W(`werkzeug ${e}: Zugang und Tarif geklaert`);const o=await ho(e,t,P,H);if(W(`werkzeug ${e}: Brain-Werkzeug fertig`),o!==null){typeof t.instance_id=="string"&&t.instance_id&&Hn(t.instance_id,e,String(o??"")),!ye&&x&&(ye=!0,rt("first_call_success")||(it("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??j??""})));const r=t.instance_id??j??"",m=x?{api_key:x,instance_id:r}:{instance_id:r};if(e==="recall_best_solution")C("recall_best_solution",m);else if(e==="learn_from_attempts")C("learn_from_attempts",m);else if(e==="session_start"){C("session_start",m,{born_at:void 0,recalls_total:void 0,starter_seeded:!1});const f=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),k=f.includes("Welcome! Your AI Brain is live.");if(!Xo(r)){if(!k&&f.length>100)C("recall_best_solution",m);else if(k&&t.workspace_path&&await On(r))try{const T=await Se("brain_from_git",{instance_id:r,repo_path:t.workspace_path,limit:50},P,H);if(T!==null){C("brain_from_git",{...m,...he??{}}),C("recall_best_solution",m);let I="";if((he?.total??0)===0)try{const A=await ke("brain_seed_starter",{instance_id:r},P,H);A&&(C("brain_seed_starter",{...m,auto:!0},{seeded_count:16,auto:!0}),I=`
|
|
35
35
|
---
|
|
36
36
|
`+String(A))}catch{}const E=String(T),M=he?.total??0,v=M>0?`
|
|
37
37
|
\u2705 **Brain bootstrapped from git \u2014 ${M} lesson${M===1?"":"s"} loaded.** Your AI already knows your history.`:"";if(E||I||v)return String(o)+v+`
|
|
@@ -42,7 +42,7 @@ cachly: code ${t.userCode}
|
|
|
42
42
|
> Run \`brain_from_git(instance_id="`+r+'", repo_path="'+String(t.workspace_path)+'")` manually to seed it.\n> Or try `brain_seed_starter` to load 16 universal engineering lessons instantly.'}}}else if(e==="session_end")C("session_end",m);else if(e==="smart_recall"){const f=typeof o=="object"&&o!==null&&"content"in o?JSON.stringify(o):String(o??""),k=f.length>50&&!f.includes("No lessons found")&&!f.includes("no lessons")&&!f.includes("No matches found");if(C("smart_recall",m,{hit:k,topic:String(t.query??"").slice(0,80)}),k&&C("recall_best_solution",m),re&&typeof o=="string")return`> \u26A0\uFE0F **Brain auth degraded** \u2014 ${re.split(`
|
|
43
43
|
`)[0]}
|
|
44
44
|
|
|
45
|
-
${o}`}return o}const c=await
|
|
45
|
+
${o}`}return o}const c=await yo(e,t,P,H);if(c!==null)return!ye&&x&&(ye=!0,rt("first_call_success")||(it("first_call_success"),C("first_call_success",{tool:e,instance_id:t.instance_id??j??""}))),c;const i=await bo(e,t,P,H);if(i!==null)return i;const a=await vo(e,t,P,H);if(a!==null)return a;const g=r=>s?r+s:r,d=await wo(e,t,P,H);if(d!==null)return g(d);const l=await xo(e,t,P,H);if(l!==null)return l;const p=await _o(e,t,P,H);if(p!==null)return g(p);const y=await $o(e,t,P,H);if(y!==null){if(e==="brain_predict"){const r=t.instance_id??j??"";C("brain_predict",x?{api_key:x,instance_id:r}:{instance_id:r})}return g(y)}const w=await ke(e,t,P,H);if(w!==null)return w;const b=await $n(e,t,P,H);if(b!==null)return b;const u=await Se(e,t,P,H);if(u!==null){const r=t.instance_id??j??"",m=x?{api_key:x,instance_id:r}:{instance_id:r};if(e==="brain_from_git"){const f=he;C("brain_from_git",{...m,...f??{}},f?{fixes:f.fixes,features:f.features,refactors:f.refactors,total:f.total}:void 0)}else e==="brain_predict_failures"&&C("brain_predict_failures",m);return u}switch(e){case"get_api_status":{let r="unknown";try{const T=await fetch(`${_}/health`,{signal:AbortSignal.timeout(8e3)});if(T.ok){const S=await T.json();r=`${S.status??"ok"} (db: ${S.db??"?"})`}else r=`HTTP ${T.status}`}catch(T){r=`unreachable: ${T.message}`}if(!x)return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${_}`,` \u{1F493} Health: ${r}`," \u{1F511} Auth: \u274C CACHLY_JWT not set","",`\u{1F4A1} Get your API token at ${N("/instances","api-status")} \u2192 Settings \u2192 API Token`].join(`
|
|
46
46
|
`);let m="\u274C invalid JWT format";try{const T=x.split(".");if(T.length===3){const S=JSON.parse(Buffer.from(T[1],"base64url").toString("utf-8")),I=S.sub??"(unknown)",E=S.iss??"(unknown)",M=E.includes("keycloak")?"Keycloak":"OIDC",v=S.exp?new Date(S.exp*1e3):null,A=v?v<new Date:!1;m=["\u2705 JWT decoded",` Sub (user ID): ${I}`,` Provider: ${M}`,` Issuer: ${E}`,` Expires: ${v?v.toISOString():"never"} ${A?"\u26A0\uFE0F EXPIRED \u2013 get a new token!":"\u2705"}`].join(`
|
|
47
47
|
`)}}catch{m="\u274C JWT decode failed \u2013 check CACHLY_JWT format"}let f="";try{const S=(await H("/api/v1/instances")).data??[];if(S.length===0)f=`
|
|
48
48
|
|
|
@@ -53,17 +53,17 @@ ${o}`}return o}const c=await ho(e,t,P,H);if(c!==null)return!ye&&x&&(ye=!0,st("fi
|
|
|
53
53
|
|
|
54
54
|
\u{1F9E0} **Brain Instances:** could not fetch \u2014 ${T.message}`}await Ce();const k=xe(x),B=k.state==="long_lived"?"\u{1F6E1}\uFE0F Self-healing: \u2705 long-lived API key (won't expire silently)":k.state==="healthy"?`\u{1F6E1}\uFE0F Self-healing: \u2705 token valid${k.expiresInMs?` (${Math.round(k.expiresInMs/36e5)}h left)`:""}`:k.state==="near_expiry"?"\u{1F6E1}\uFE0F Self-healing: \u267B\uFE0F token near expiry \u2014 auto-refresh attempted":`\u{1F6E1}\uFE0F Self-healing: \u26A0\uFE0F ${k.message.split(`
|
|
55
55
|
`)[0]}`;return["\u{1F4E1} **cachly API Status**","",` \u{1F310} API: ${_}`,` \u{1F493} Health: ${r}`,` ${B}`,"","\u{1F511} **Auth:**",m,f].join(`
|
|
56
|
-
`)}default:throw new
|
|
56
|
+
`)}default:throw new pt(`Unknown tool: ${e}`)}}class pt extends Error{}const ut=`This project has a Cachly AI Brain \u2014 persistent, cross-session memory of past fixes, decisions, and gotchas for THIS codebase. Use it proactively; it makes you faster and stops you repeating known mistakes.
|
|
57
57
|
|
|
58
58
|
- BEFORE a non-trivial task: call smart_recall with a short description of what you're about to do. If it returns lessons, apply them before researching from scratch.
|
|
59
59
|
- WHEN debugging an error: call causal_trace with the exact error first \u2014 a known fix may already exist.
|
|
60
60
|
- AFTER a fix, deploy, or discovery: call learn_from_attempts so the knowledge persists.
|
|
61
61
|
- BEFORE a risky op (deploy, migration, dependency bump): call brain_predict.
|
|
62
62
|
|
|
63
|
-
The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,
|
|
63
|
+
The Brain instance id comes from the CACHLY_BRAIN_INSTANCE_ID environment variable.`,mt={tools:{},resources:{},prompts:{}},gt=async()=>{const{katalog:e,unbekannteKernnamen:t}=mn(le);return t.length>0&&console.error(`cachly: ${t.length} Kernwerkzeug(e) gibt es gar nicht: ${t.join(", ")}`),{tools:e}};async function ft(){return{resources:[]}}async function ht(){return{resourceTemplates:[]}}async function yt(){return{prompts:[]}}function Mn(e){e.setRequestHandler(Je,gt),e.setRequestHandler(Pe,wt),e.setRequestHandler(De,ft),e.setRequestHandler(Me,ht),e.setRequestHandler(Oe,yt)}function Dn(){const e=new He({name:"cachly-mcp",version:D},{capabilities:mt,instructions:ut});return Mn(e),bt(e),e}function bt(e){const t=e.oninitialized;e.oninitialized=()=>{try{const n=e.getClientVersion();kt(n?.name,n?.version)}catch{}t?.()}}const G=new He({name:"cachly-mcp",version:D},{capabilities:mt,instructions:ut});bt(G),G.setRequestHandler(Je,gt),G.setRequestHandler(De,ft),G.setRequestHandler(Me,ht),G.setRequestHandler(Oe,yt);let Te=null,de=!1,V=null,vt=0;async function Jn(e){if(!de){if(V){await V;return}V=(async()=>{de=!0,Te=e;try{await U("session_start",{instance_id:e,focus:"auto (MCP session)",workspace_path:process.cwd()})}catch{}finally{V=null}})(),await V,process.env.CACHLY_AUTO_INDEX!=="false"&&(async()=>{const t=await P(e),n=await t.get(`cachly:index:last_indexed:${e}`),s=1440*60*1e3;(!n||Date.now()-parseInt(n,10)>s)&&(await t.set(`cachly:index:last_indexed:${e}`,String(Date.now()),"EX",9e4),await U("index_project",{instance_id:e,dir:process.cwd(),max_files:150,ttl:86400*7,namespace:"cachly:sem:code",hintergrund:!0}))})().catch(()=>{})}}async function Ie(){if(!(!de||!Te)){de=!1;try{await U("session_end",{instance_id:Te,summary:`Auto-ended after ${vt} tool call(s). Session was started automatically.`,files_changed:[],lessons_learned:0})}catch{}}}const wt=async e=>{let{name:t,arguments:n}=e.params;if(t===st){const o=n??{},c=typeof o.tool=="string"?o.tool:"";if(!c)return{content:[{type:"text",text:'cachly_tool braucht das Feld "tool" \u2014 den Namen des Werkzeugs.'}],isError:!0};const i=le.find(a=>a.name===c);if(!i)return{content:[{type:"text",text:`Kein Werkzeug namens "${c}". Die Liste steht in der Beschreibung von ${st}.`}],isError:!0};if(o.describe===!0)return{content:[{type:"text",text:JSON.stringify({name:i.name,description:i.description,inputSchema:i.inputSchema},null,2)}]};t=c,n=o.arguments??{}}const s=new Set(["session_start","session_start_summary","session_end","auto_learn_session"]);if(!s.has(t)&&!de&&!V){const o=Ae(n?.instance_id)||j||Ae(process.env.CACHLY_BRAIN_INSTANCE_ID);o&&await Jn(o).catch(()=>{})}else V&&await V.catch(()=>{});s.has(t)||vt++;try{pn(),W(`werkzeug ${t}: Anfang`);const o=await U(t,n??{});return W(`werkzeug ${t}: Antwort fertig`),{content:[{type:"text",text:jo(t,o)+nn()+ln(t)}]}}catch(o){if(o instanceof pt)return{content:[{type:"text",text:o.message}],isError:!0};if(o instanceof Q)throw o;const c=o.message??String(o);throw Be("cachly","tool_error",{tool:t,error:c}).catch(()=>{}),new Q(se.InternalError,c)}};G.setRequestHandler(Pe,wt),process.on("SIGTERM",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)await e.quit().catch(()=>{});process.exit(0)}),process.on("SIGINT",async()=>{await Ie().catch(()=>{});for(const[,e]of ee)await e.quit().catch(()=>{});process.exit(0)}),process.on("unhandledRejection",e=>{const t=e instanceof Error?e.message:String(e);process.stderr.write(`[cachly-mcp] unhandledRejection: ${t}
|
|
64
64
|
`)}),process.on("uncaughtException",e=>{process.stderr.write(`[cachly-mcp] uncaughtException: ${e?.stack??String(e)}
|
|
65
|
-
`)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const be={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"};function
|
|
66
|
-
`)}catch{}}if(s==="continue"){const p=a.experimental??{},y=p.modelContextProtocolServers??[];let w;for(const u of y){const r=u.env??{};if(r.CACHLY_JWT){w=r.CACHLY_JWT;break}}w&&pe(w,c);const b=y.filter(u=>{const r=u.env??{};return!r.CACHLY_JWT&&!r.CACHLY_BRAIN_INSTANCE_ID});return b.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:i.env}),a.experimental={...p,modelContextProtocolServers:b},JSON.stringify(a,null,2)}if(s==="zed"){const p=a.context_servers??{},w=p.cachly?.command?.env?.CACHLY_JWT;return w&&pe(w,c),p.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:i.env},settings:{}},a.context_servers=p,JSON.stringify(a,null,2)}if(
|
|
65
|
+
`)}),process.stdout.on("error",()=>{}),process.stdin.on("error",()=>{});const be={claude:".mcp.json",cursor:".cursor/mcp.json",windsurf:".windsurf/mcp.json",copilot:".vscode/mcp.json",continue:".continue/config.json",cline:".vscode/mcp.json",zed:".zed/settings.json"};function Yn(e,t){const n=Object.entries(t).map(([s,o])=>`${s}=${o}`);return e==="codex"?{befehl:`codex mcp add cachly ${n.map(s=>`--env ${s}`).join(" ")} -- npx -y @cachly-dev/mcp-server@latest`,wo:"~/.codex/config.toml"}:e==="gemini"?{befehl:`gemini mcp add -s project ${n.map(s=>`-e ${s}`).join(" ")} cachly npx -- -y @cachly-dev/mcp-server@latest`,wo:".gemini/settings.json"}:null}const Ee="<!-- cachly-brain-start -->",xt="<!-- cachly-brain-end -->",_t="https://api.cachly.dev";function oe(e,t,n={}){const s={CACHLY_BRAIN_INSTANCE_ID:t};return n.includeApiKey&&(s.CACHLY_JWT=e),_&&_!==_t&&(s.CACHLY_API_URL=_),s}function Un(e,t,n){return n==="continue"?JSON.stringify({experimental:{modelContextProtocolServers:[{transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:oe(e,t)}]}},null,2):n==="zed"?JSON.stringify({context_servers:{cachly:{command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)},settings:{}}}},null,2):$t(n)?JSON.stringify({servers:{cachly:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2):JSON.stringify({mcpServers:{cachly:{command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(e,t)}}},null,2)}function $t(e){return be[e]===".vscode/mcp.json"}function pe(e,t){Do(e)||te(e,t)}async function Ct(e,t,n,s,o,c={}){const i={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(t,n)};if(!o.existsSync(e))return Un(t,n,s);let a={};try{a=JSON.parse(await o.readFile(e,"utf-8"))}catch{try{const{rename:p}=await import("node:fs/promises");await p(e,e+".bak"),process.stderr.write(`\u26A0\uFE0F ${e} was not valid JSON \u2014 backed up to ${e}.bak
|
|
66
|
+
`)}catch{}}if(s==="continue"){const p=a.experimental??{},y=p.modelContextProtocolServers??[];let w;for(const u of y){const r=u.env??{};if(r.CACHLY_JWT){w=r.CACHLY_JWT;break}}w&&pe(w,c);const b=y.filter(u=>{const r=u.env??{};return!r.CACHLY_JWT&&!r.CACHLY_BRAIN_INSTANCE_ID});return b.push({transport:{type:"stdio",command:"npx",args:["-y","@cachly-dev/mcp-server@latest"]},env:i.env}),a.experimental={...p,modelContextProtocolServers:b},JSON.stringify(a,null,2)}if(s==="zed"){const p=a.context_servers??{},w=p.cachly?.command?.env?.CACHLY_JWT;return w&&pe(w,c),p.cachly={command:{path:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:i.env},settings:{}},a.context_servers=p,JSON.stringify(a,null,2)}if($t(s)){const p=a.mcpServers??void 0,w=p?.cachly?.env?.CACHLY_JWT;w&&pe(w,c),p&&"cachly"in p&&(delete p.cachly,Object.keys(p).length===0&&delete a.mcpServers);const b=a.servers??{},u=b.cachly,r=u?.env?.CACHLY_JWT;return r&&pe(r,c),b.cachly=u?.envFile?{type:"stdio",...i,envFile:u.envFile}:{type:"stdio",...i},a.servers=b,JSON.stringify(a,null,2)}const g=a.mcpServers??{},l=g.cachly?.env?.CACHLY_JWT;return l&&pe(l,c),g.cachly=i,a.mcpServers=g,JSON.stringify(a,null,2)}function St(e){return`${Ee}
|
|
67
67
|
## Cachly AI Brain \u2014 Always Active
|
|
68
68
|
|
|
69
69
|
The Brain MCP server runs automatically. Instance: \`${e}\`
|
|
@@ -118,14 +118,14 @@ Report predicted failure risks to the user before proceeding.
|
|
|
118
118
|
|
|
119
119
|
### Half-finished code rule:
|
|
120
120
|
Never commit code that does not compile. Run \`tsc --noEmit\` / \`go build ./...\` before every commit.
|
|
121
|
-
${
|
|
121
|
+
${xt}`}const Wn=`---
|
|
122
122
|
description: Cachly AI Brain \u2014 persistent memory protocol (recall before tasks, learn after fixes)
|
|
123
123
|
alwaysApply: true
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
`;async function
|
|
127
|
-
`+
|
|
128
|
-
`,p={};for(const{path:y,prefix:w}of d){if(await c(g(y),{recursive:!0}),i(y)){const b=await o(y,"utf-8");if(b.includes(Ee)){const u=b.replace(new RegExp(`${Ee}[\\s\\S]*?${
|
|
126
|
+
`;async function At(e,t){const{writeFile:n,appendFile:s,readFile:o,mkdir:c}=await import("node:fs/promises"),{existsSync:i}=await import("node:fs"),{resolve:a,dirname:g}=await import("node:path"),d=[{path:a(e,"CLAUDE.md")},{path:a(e,"AGENTS.md")},{path:a(e,".github","copilot-instructions.md")},{path:a(e,".cursor","rules","cachly.mdc"),prefix:Wn},{path:a(e,".windsurfrules")},{path:a(e,".clinerules")},...i(a(e,".idea"))?[{path:a(e,".aiassistant","rules","cachly.md")}]:[]],l=`
|
|
127
|
+
`+St(t)+`
|
|
128
|
+
`,p={};for(const{path:y,prefix:w}of d){if(await c(g(y),{recursive:!0}),i(y)){const b=await o(y,"utf-8");if(b.includes(Ee)){const u=b.replace(new RegExp(`${Ee}[\\s\\S]*?${xt}`),St(t));await n(y,u,"utf-8"),p[y]="updated";continue}await s(y,l,"utf-8"),p[y]="appended";continue}await n(y,(w??"")+l.trimStart(),"utf-8"),p[y]="written"}return p}if(process.argv[2]==="digest"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
|
|
129
129
|
\u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
|
|
130
130
|
`),process.exit(1)),process.stdout.write(`
|
|
131
131
|
\u{1F9E0} Fetching your weekly Brain digest...
|
|
@@ -136,13 +136,13 @@ alwaysApply: true
|
|
|
136
136
|
\u274C Could not fetch digest: ${n.message}
|
|
137
137
|
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="export"){const{writeFile:e,mkdir:t}=await import("node:fs/promises"),{resolve:n}=await import("node:path"),s=process.argv.slice(3),o=d=>{const l=s.indexOf(`--${d}`);return l!==-1?s[l+1]:void 0},c=o("format")??"both";c!=="md"&&c!=="jsonl"&&c!=="both"&&(console.log(`
|
|
138
138
|
\u274C Unknown --format "${c}" \u2014 use md, jsonl, or both.
|
|
139
|
-
`),process.exit(1));const i=n(o("out")??"."),a=x||
|
|
139
|
+
`),process.exit(1));const i=n(o("out")??"."),a=x||et()||"",g=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!a||!g)&&(console.log(`
|
|
140
140
|
\u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
|
|
141
141
|
`),process.exit(1)),process.stdout.write(`
|
|
142
142
|
\u{1F4E4} Exporting your Brain...
|
|
143
143
|
|
|
144
|
-
`);try{let d=[],l="";const p=await fetch(`${_}/api/v1/instances/${g}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(p.ok){const w=await p.json();d=(w.lessons??[]).map(
|
|
145
|
-
`),process.exit(0)),await t(i,{recursive:!0});const y=[];if(c==="md"||c==="both"){const w=n(i,"lessons.md");await e(w,
|
|
144
|
+
`);try{let d=[],l="";const p=await fetch(`${_}/api/v1/instances/${g}/export`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(12e4)});if(p.ok){const w=await p.json();d=(w.lessons??[]).map(hn).filter(b=>b!==null),w.complete===!1&&(l=w.note??"the server reported an incomplete read")}else if(p.status===404){const w=await fetch(`${_}/api/v1/instances/${g}/memory`,{headers:{Authorization:`Bearer ${a}`},signal:AbortSignal.timeout(8e3)});if(!w.ok)throw new Error(`memory HTTP ${w.status}`);d=((await w.json()).top_lessons??[]).map(u=>({topic:u.topic,outcome:u.outcome,severity:u.severity,tags:u.tags,whatWorked:u.what_worked,ts:u.ts,author:u.author,recallCount:u.recall_count})),l="this server has no /export endpoint yet, so this is the DASHBOARD SUMMARY: at most 50 lessons, each shortened to 120 characters. Update the server for a full export."}else throw new Error(`export HTTP ${p.status}`);d.length===0&&(console.log(` No lessons in this Brain yet \u2014 nothing to export.
|
|
145
|
+
`),process.exit(0)),await t(i,{recursive:!0});const y=[];if(c==="md"||c==="both"){const w=n(i,"lessons.md");await e(w,gn(d),"utf-8"),y.push(`${d.length} lesson${d.length===1?"":"s"} \u2192 ${w}`)}if(c==="jsonl"||c==="both"){const w=n(i,"lessons.jsonl");await e(w,fn(d),"utf-8"),y.push(`${d.length} lesson${d.length===1?"":"s"} \u2192 ${w}`)}l?(console.log("\u26A0\uFE0F Export INCOMPLETE \u2014 this is not your whole Brain:"),console.log(` ${l}`),console.log("")):console.log("\u2705 Export complete:");for(const w of y)console.log(` ${w}`);console.log("")}catch(d){console.log(`
|
|
146
146
|
\u274C Could not export your Brain: ${d.message}
|
|
147
147
|
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="invite"){const e=process.env.CACHLY_JWT??"";e||(console.log(`
|
|
148
148
|
\u26A0\uFE0F CACHLY_JWT must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot
|
|
@@ -177,7 +177,7 @@ Try it free: ${s}
|
|
|
177
177
|
`),process.exit(1)),console.log(` \u2705 Signed in!
|
|
178
178
|
`)}}catch(S){console.log(`
|
|
179
179
|
\u26A0\uFE0F Could not start sign-in: ${S.message}`),console.log(` Set CACHLY_JWT manually from ${N("/setup-ai","join")}
|
|
180
|
-
`),process.exit(1)}}const f=process.cwd(),k=i(),B=[{label:".mcp.json (Claude Code project)",path:o(f,".mcp.json")},{label:".cursor/mcp.json",path:o(f,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(f,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(f,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(k,".claude","mcp.json"),global:!0}];let T=0;for(const{label:S,path:I,global:E}of B){const M=c(I);if(!(!E&&!s(M)&&!s(I)))try{await n(M,{recursive:!0});let v={};if(s(I))try{v=JSON.parse(await t(I,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(I,I+".bak")}catch{}}const A=v.mcpServers??{},F=A.cachly??{},z=F.env??{};z.CACHLY_BRAIN_INSTANCE_ID=l,m&&!z.CACHLY_JWT&&(z.CACHLY_JWT=m),_!==
|
|
180
|
+
`),process.exit(1)}}const f=process.cwd(),k=i(),B=[{label:".mcp.json (Claude Code project)",path:o(f,".mcp.json")},{label:".cursor/mcp.json",path:o(f,".cursor","mcp.json")},{label:".windsurf/mcp.json",path:o(f,".windsurf","mcp.json")},{label:".vscode/mcp.json (Copilot/Cline)",path:o(f,".vscode","mcp.json")},{label:"~/.claude/mcp.json (global)",path:o(k,".claude","mcp.json"),global:!0}];let T=0;for(const{label:S,path:I,global:E}of B){const M=c(I);if(!(!E&&!s(M)&&!s(I)))try{await n(M,{recursive:!0});let v={};if(s(I))try{v=JSON.parse(await t(I,"utf-8"))}catch{try{await(await import("node:fs/promises")).rename(I,I+".bak")}catch{}}const A=v.mcpServers??{},F=A.cachly??{},z=F.env??{};z.CACHLY_BRAIN_INSTANCE_ID=l,m&&!z.CACHLY_JWT&&(z.CACHLY_JWT=m),_!==_t&&(z.CACHLY_API_URL=_),A.cachly={...F,command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:z},v.mcpServers=A,await e(I,JSON.stringify(v,null,2),"utf-8"),console.log(` \u2705 ${S}`),T++}catch(v){v.code!=="ENOENT"&&console.log(` \u26A0\uFE0F ${S}: ${v.message}`)}}console.log(""),T===0?console.log(" \u26A0\uFE0F No editor configs found \u2014 run `cachly setup` first.\n"):(console.log(` \u{1F9E0} You're now sharing Brain: \x1B[1m${p}\x1B[0m`),console.log(` Restart your editor \u2014 your AI arrives pre-briefed from the team Brain.
|
|
181
181
|
`),console.log(" \u{1F4DB} Add the badge to your README:"),console.log(` npx @cachly-dev/mcp-server@latest badge
|
|
182
182
|
`)),process.exit(0)}if(process.argv[2]==="upgrade"){process.stdout.write(`
|
|
183
183
|
\u23F3 Checking for updates...
|
|
@@ -194,7 +194,7 @@ Try it free: ${s}
|
|
|
194
194
|
`),process.exit(0));let i="";try{i=e("git config user.name",{cwd:c,encoding:"utf-8",stdio:"pipe"}).trim().split(" ")[0]??""}catch{}let a=o(c);try{const v=JSON.parse(n(s(c,"package.json"),"utf-8"));v.name&&(a=v.name.replace(/^@[^/]+\//,""))}catch{}let g="";try{g=e('git log HEAD --pretty=format:"%H|||%s|||%ad|||%an" --date=short --no-merges -n 200',{cwd:c,encoding:"utf-8",stdio:"pipe"})}catch{console.log(`\u26A0\uFE0F Could not read git log. Make sure you have commits.
|
|
195
195
|
`),process.exit(0)}const d=g.trim().split(`
|
|
196
196
|
`).filter(Boolean).map(v=>{const[A,F,z,ne]=v.split("|||");return{sha:(A??"").trim().slice(0,8),subject:(F??"").trim(),date:(z??"").trim(),author:(ne??"").trim()}});d.length===0&&(console.log(`\u26A0\uFE0F No commits found.
|
|
197
|
-
`),process.exit(0));const l=new Map,p=[],y=[],w=[],b=new Set;let u=0;for(const v of d){const A
|
|
197
|
+
`),process.exit(0));const l=new Map,p=[],y=[],w=[],b=new Set;let u=0;for(const v of d){const A=Cn(v.subject);l.set(A,(l.get(A)??0)+1),Sn(v.subject)&&u++,A==="fix"&&p.length<5&&p.push(v.subject.slice(0,72)),A==="feat"&&y.length<5&&y.push(v.subject.slice(0,72)),A==="security"&&w.length<3&&w.push(v.subject.slice(0,72)),v.author&&b.add(v.author)}const r=An(d.map(v=>v.subject)),m=`${d[d.length-1]?.date??"?"} \u2192 ${d[0]?.date??"?"}`,f=r>=501?"Oracle":r>=201?"Architect":r>=51?"Expert":r>=11?"Explorer":"Apprentice",B=`${i?`Hey ${i} \u2014 `:""}here's what your AI would know about ${a}`;process.stdout.write("\x1B[2K\r"),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log(`\u2502 \x1B[1m\u{1F9E0} ${B.slice(0,58).padEnd(58)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Commits analysed : \x1B[33m${String(d.length).padEnd(6)}\x1B[0m Date range: \x1B[90m${m.slice(0,23).padEnd(23)}\x1B[0m \u2502`),console.log(`\u2502 Lessons extracted: \x1B[32m${String(r).padEnd(6)}\x1B[0m Contributors: \x1B[36m${String(b.size).padEnd(20)}\x1B[0m\u2502`),console.log(`\u2502 Brain Level : \x1B[35m${f.padEnd(10)}\x1B[0m Reverts: \x1B[33m${String(u).padEnd(21)}\x1B[0m\u2502`),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");const T=[...l.entries()].filter(([v])=>v!=="chore").sort((v,A)=>A[1]-v[1]),S=(v,A)=>"\u2588".repeat(Math.round(v/A*20)).padEnd(20),I=Math.max(...T.map(([,v])=>v),1);console.log("\u2502 \x1B[90mCategory breakdown:\x1B[0m \u2502");for(const[v,A]of T){const F={fix:"\u{1F527}",feat:"\u2728",perf:"\u26A1",security:"\u{1F512}",deploy:"\u{1F680}",refactor:"\u{1F504}"}[v]??"\u2022";console.log(`\u2502 ${F} \x1B[36m${v.padEnd(10)}\x1B[0m \x1B[35m${S(A,I)}\x1B[0m \x1B[33m${String(A).padStart(3)}\x1B[0m \u2502`)}if(w.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[31m\u{1F512} Security fixes your AI would know:\x1B[0m \u2502");for(const v of w)console.log(`\u2502 \x1B[90m\u2022 ${v.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(p.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[33m\u{1F527} Bug fixes your AI would never repeat:\x1B[0m \u2502");for(const v of p.slice(0,4))console.log(`\u2502 \x1B[90m\u2022 ${v.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}if(y.length>0){console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u2728 Features & decisions it would recall:\x1B[0m \u2502");for(const v of y.slice(0,3))console.log(`\u2502 \x1B[90m\u2022 ${v.slice(0,58).padEnd(58)}\x1B[0m \u2502`)}console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 \x1B[32m\u{1F4A1} With cachly, your AI arrives pre-briefed every session.\x1B[0m \u2502"),console.log("\u2502 \x1B[32m No more re-explaining. No more repeated mistakes.\x1B[0m \u2502"),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),console.log("");const E=new URLSearchParams({repo:a,commits:String(d.length),lessons:String(r),level:f,authors:String(b.size),reverts:String(u)}),M=N(`/preview?${E.toString()}`,"demo");console.log(" \x1B[1mMake this permanent (free, 1\u20135 minutes):\x1B[0m"),console.log(" \x1B[32m$ npx @cachly-dev/mcp-server@latest autopilot\x1B[0m"),console.log(""),console.log(` \x1B[90m\u{1F517} Shareable preview:\x1B[0m \x1B[36m${M}\x1B[0m`),console.log(""),console.log(" Works with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 Copilot \xB7 Cline \xB7 Zed"),console.log(" GDPR \xB7 German servers \xB7 free tier, no credit card"),console.log(""),process.exit(0)}if(process.argv[2]==="share"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
|
|
198
198
|
\u26A0\uFE0F CACHLY_JWT and CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
|
|
199
199
|
`),process.exit(1)),process.stdout.write(`
|
|
200
200
|
\u{1F9E0} Fetching your Brain stats...
|
|
@@ -222,14 +222,14 @@ ${l}
|
|
|
222
222
|
`),process.exit(1)),process.stdout.write(e(le,t,D)+`
|
|
223
223
|
`,()=>process.exit(0))}if(process.argv[2]==="badge"){const e=process.env.CACHLY_BRAIN_INSTANCE_ID??"";e||(console.log(`
|
|
224
224
|
\u26A0\uFE0F CACHLY_BRAIN_INSTANCE_ID must be set.`),console.log(` Run: npx @cachly-dev/mcp-server@latest autopilot (takes 1\u20135 minutes)
|
|
225
|
-
`),process.exit(1));const t=`${_}/api/v1/badge/${e}`,n=N("/","badge"),s=`[](${n})`,o=`<a href="${n}"><img src="${t}" alt="cachly Brain" /></a>`;console.log(""),console.log("\x1B[35m \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly Brain Badge\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(" Paste into your README.md:"),console.log(""),console.log(` \x1B[32m${s}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Or paste into HTML:"),console.log(""),console.log(` \x1B[36m${o}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Badge URL (live, updates every hour):"),console.log(` \x1B[90m${t}\x1B[0m`),console.log(""),console.log(" \x1B[2mThe badge shows your current lesson count \u2014 no auth required,"),console.log(" safe to embed in public repos. Updates hourly.\x1B[0m"),console.log(""),process.exit(0)}!process.argv[2]&&process.stdout.isTTY&&(console.log(""),console.log("\x1B[35m \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly \u2014 Persistent AI Memory for Developers\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(" Stop re-teaching your AI every morning."),console.log(" cachly gives it a permanent brain \u2014 pre-briefed every session."),console.log(""),console.log(" \x1B[1mCommands:\x1B[0m"),console.log(" \x1B[1m\x1B[32m npx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" \x1B[32m npx @cachly-dev/mcp-server@latest demo\x1B[0m \u2190 Try it first (no account)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest setup\x1B[0m \u2190 Interactive setup (pick editors)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest claim\x1B[0m \u2190 Keep a test Brain in your own account"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest health\x1B[0m \u2190 Check everything works"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest doctor\x1B[0m \u2190 Diagnose a broken or missing install"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest digest\x1B[0m \u2190 Weekly Brain summary"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest share\x1B[0m \u2190 Share your Brain stats"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest badge\x1B[0m \u2190 README badge for your Brain"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest invite\x1B[0m \u2190 Invite a teammate"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest join <token>\x1B[0m \u2190 Accept a Brain invite"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest bench\x1B[0m \u2190 Recall quality vs flat-file memory"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest upgrade\x1B[0m \u2190 Check for updates"),console.log(""),console.log(" \x1B[90mWorks with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 GitHub Copilot \xB7 Cline \xB7 Zed\x1B[0m"),console.log(` \x1B[90mGDPR \xB7 German servers \xB7 ${le.length} MCP tools\x1B[0m`),console.log(""),process.exit(0));const
|
|
225
|
+
`),process.exit(1));const t=`${_}/api/v1/badge/${e}`,n=N("/","badge"),s=`[](${n})`,o=`<a href="${n}"><img src="${t}" alt="cachly Brain" /></a>`;console.log(""),console.log("\x1B[35m \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly Brain Badge\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(" Paste into your README.md:"),console.log(""),console.log(` \x1B[32m${s}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Or paste into HTML:"),console.log(""),console.log(` \x1B[36m${o}\x1B[0m`),console.log(""),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(" Badge URL (live, updates every hour):"),console.log(` \x1B[90m${t}\x1B[0m`),console.log(""),console.log(" \x1B[2mThe badge shows your current lesson count \u2014 no auth required,"),console.log(" safe to embed in public repos. Updates hourly.\x1B[0m"),console.log(""),process.exit(0)}!process.argv[2]&&process.stdout.isTTY&&(console.log(""),console.log("\x1B[35m \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\x1B[0m"),console.log("\x1B[35m \u2551\x1B[0m \x1B[1m\u{1F9E0} cachly \u2014 Persistent AI Memory for Developers\x1B[0m \x1B[35m\u2551\x1B[0m"),console.log("\x1B[35m \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\x1B[0m"),console.log(""),console.log(" Stop re-teaching your AI every morning."),console.log(" cachly gives it a permanent brain \u2014 pre-briefed every session."),console.log(""),console.log(" \x1B[1mCommands:\x1B[0m"),console.log(" \x1B[1m\x1B[32m npx @cachly-dev/mcp-server@latest autopilot\x1B[0m \u2190 \x1B[1mOne command, fully ready\x1B[0m"),console.log(" \x1B[32m npx @cachly-dev/mcp-server@latest demo\x1B[0m \u2190 Try it first (no account)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest setup\x1B[0m \u2190 Interactive setup (pick editors)"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest claim\x1B[0m \u2190 Keep a test Brain in your own account"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest health\x1B[0m \u2190 Check everything works"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest doctor\x1B[0m \u2190 Diagnose a broken or missing install"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest digest\x1B[0m \u2190 Weekly Brain summary"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest share\x1B[0m \u2190 Share your Brain stats"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest badge\x1B[0m \u2190 README badge for your Brain"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest invite\x1B[0m \u2190 Invite a teammate"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest join <token>\x1B[0m \u2190 Accept a Brain invite"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest bench\x1B[0m \u2190 Recall quality vs flat-file memory"),console.log(" \x1B[36m npx @cachly-dev/mcp-server@latest upgrade\x1B[0m \u2190 Check for updates"),console.log(""),console.log(" \x1B[90mWorks with: Claude Code \xB7 Cursor \xB7 Windsurf \xB7 GitHub Copilot \xB7 Cline \xB7 Zed\x1B[0m"),console.log(` \x1B[90mGDPR \xB7 German servers \xB7 ${le.length} MCP tools\x1B[0m`),console.log(""),process.exit(0));const Fn={cursor:{datei:".cursor/hooks.json",name:"Cursor",wie:"session briefing, per-prompt recall after the first tool call"},copilot:{datei:Eo,name:"VS Code / Copilot",wie:"session briefing, per-prompt recall"},codex:{datei:Ro,name:"Codex",wie:"session briefing, per-prompt recall; trust it once in /hooks"},gemini:{datei:No,name:"Gemini CLI",wie:"session briefing, per-prompt recall"}};function zn(e,t,n){if(!t)return;const{datei:s,name:o,wie:c}=Fn[e];if(t.hooks==="skipped"){console.log(`\u26A0\uFE0F ${n}${s} ${t.grund??"is not valid JSON"} \u2014 left untouched, ${o} hooks not wired`);return}const i=t.hooks==="unchanged"?"\u2713 ":"\u2705 ",a=t.hooks==="written"?"Written":t.hooks==="merged"?"Merged":"Already wired";console.log(`${i}${n}${a}: ${s} (Ambient Recall for ${o} \u2014 ${c})`)}async function ue(e,t,n,s){const o={cursor:Ao,copilot:ko,codex:To,gemini:Io}[e];zn(e,await o(t,n).catch(()=>null),s)}if(process.argv[2]==="init"){const e=Date.now(),{writeFile:t,mkdir:n,readFile:s}=await import("node:fs/promises"),{resolve:o,dirname:c}=await import("node:path"),i=process.argv.slice(3),a=r=>{const m=i.indexOf(`--${r}`);return m!==-1?i[m+1]:void 0};let g=a("instance-id")??process.env.CACHLY_BRAIN_INSTANCE_ID,d=a("api-key")??process.env.CACHLY_JWT;const l=(a("editor")??"claude").toLowerCase(),p=o(a("project-dir")??"."),y=a("api-url");if(y&&(_=y.replace(/\/+$/,"")),!g||!d)try{const{existsSync:r}=await import("node:fs"),m=process.env.HOME??process.env.USERPROFILE??"",f=m?o(m,".claude","mcp.json"):"";if(f&&r(f)){const B=JSON.parse(await s(f,"utf-8")).mcpServers?.cachly?.env??{};d??=B.CACHLY_JWT,g??=B.CACHLY_BRAIN_INSTANCE_ID,d&&g&&console.log("\u2713 Reusing credentials from ~/.claude/mcp.json (saved by a prior setup)")}}catch{}(!g||!d)&&(console.error(`
|
|
226
226
|
Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <cky_live_...> [--editor claude|cursor|windsurf|copilot|continue|codex|gemini] [--project-dir /path] [--api-url https://your-self-hosted-backend]
|
|
227
227
|
`),console.error(`First time? Run the zero-config wizard (signs you in, auto-provisions): npx @cachly-dev/mcp-server@latest autopilot
|
|
228
228
|
`),console.error(`Get your credentials from: ${N("/setup-ai","init")}
|
|
229
|
-
`),process.exit(1));const w=
|
|
230
|
-
\u{1F449} Register the MCP server once (writes ${w.wo}):`),console.log(` ${w.befehl}`);else{const r=be[l]??".mcp.json",m=o(p,r);await n(c(m),{recursive:!0});const{existsSync:f}=await import("node:fs"),k=f(m),B=k?await s(m,"utf-8").catch(()=>""):"";te(d);const T=await
|
|
229
|
+
`),process.exit(1));const w=Yn(l,oe(d,g));if(w)te(d),console.log(`
|
|
230
|
+
\u{1F449} Register the MCP server once (writes ${w.wo}):`),console.log(` ${w.befehl}`);else{const r=be[l]??".mcp.json",m=o(p,r);await n(c(m),{recursive:!0});const{existsSync:f}=await import("node:fs"),k=f(m),B=k?await s(m,"utf-8").catch(()=>""):"";te(d);const T=await Ct(m,d,g,l,{readFile:s,existsSync:f});T!==B?(await t(m,T,"utf-8"),console.log(`
|
|
231
231
|
\u2705 ${k?"Updated":"Written"}: ${r}`)):console.log(`
|
|
232
|
-
\u2713 Already configured: ${r} (no change)`)}const b=await
|
|
232
|
+
\u2713 Already configured: ${r} (no change)`)}const b=await At(p,g);for(const[r,m]of Object.entries(b)){const f=m==="updated"?"\u2705 Updated":m==="appended"?"\u2705 Appended to":"\u2705 Written",k=r.split(/[\\/]/).pop()??r;console.log(`${f}: ${k}`)}try{const r=await Ge(p,g,x||void 0);r==="written"?console.log("\u2705 Written: .git/hooks/post-commit (CLS hook)"):r==="upgraded"?console.log(`\u2705 Upgraded: .git/hooks/post-commit (CLS hook \u2192 ${Ve})`):r==="appended"?console.log("\u2705 Appended: .git/hooks/post-commit (CLS hook)"):r==="unchanged"&&console.log("\u2713 CLS hook already current in .git/hooks/post-commit")}catch{}if(l==="claude")try{const r=await Ze(p,g),m=r.scripts==="written"?"\u2705 Written":r.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Qe})`:"\u2713 Unchanged";console.log(`${m}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),r.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):r.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}catch{}(l==="cursor"||l==="copilot"||l==="codex"||l==="gemini")&&await ue(l,p,g,"");const u=((Date.now()-e)/1e3).toFixed(1);console.log(`
|
|
233
233
|
\u{1F9E0} Cachly AI Brain configured for ${l==="claude"?"Claude Code":l}! (${u}s)`),console.log(w?` Run the \`mcp add\` line above, then restart ${l} \u2014 the \`cachly\` MCP tools will appear.`:" Restart your editor \u2014 the `cachly` MCP tools will appear."),console.log(" Re-run `init` anytime \u2014 it's idempotent (only writes what changed)."),console.log(`
|
|
234
234
|
\u{1F4DB} Add a live badge to your README:`),console.log(` npx @cachly-dev/mcp-server@latest badge
|
|
235
235
|
`),process.exit(0)}if(process.argv[2]==="status"){const e=process.env.CACHLY_JWT??"",t=process.env.CACHLY_BRAIN_INSTANCE_ID??"";(!e||!t)&&(console.log(`
|
|
@@ -248,23 +248,23 @@ Usage: npx @cachly-dev/mcp-server@latest init --instance-id <uuid> --api-key <ck
|
|
|
248
248
|
${"\u2500".repeat(40)}`),c===0?console.log(`\u2705 All checks passed (${o} ok)
|
|
249
249
|
`):(console.log(`\u274C ${c} check(s) failed, ${o} passed
|
|
250
250
|
`),console.log(`\u{1F4A1} Fix issues with: npx @cachly-dev/mcp-server@latest autopilot
|
|
251
|
-
`),process.exit(1)),process.exit(0)}if(process.argv[2]==="claim"){const{readFile:e,writeFile:t}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:s}=await import("node:path"),{homedir:o}=await import("node:os"),c=r=>{const m=process.argv.indexOf(`--${r}`);return m!==-1?process.argv[m+1]:void 0};_=(c("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const i=(c("auth-url")??
|
|
251
|
+
`),process.exit(1)),process.exit(0)}if(process.argv[2]==="claim"){const{readFile:e,writeFile:t}=await import("node:fs/promises"),{existsSync:n}=await import("node:fs"),{resolve:s}=await import("node:path"),{homedir:o}=await import("node:os"),c=r=>{const m=process.argv.indexOf(`--${r}`);return m!==-1?process.argv[m+1]:void 0};_=(c("api-url")??"https://api.cachly.dev").replace(/\/+$/,"");const i=(c("auth-url")??ot).replace(/\/+$/,"");console.log(`
|
|
252
252
|
\u{1F9E0} cachly \u2014 keep your test Brain in your own account
|
|
253
|
-
`),(_!=="https://api.cachly.dev"||i!==
|
|
254
|
-
`);const a=
|
|
253
|
+
`),(_!=="https://api.cachly.dev"||i!==ot)&&console.log(`\u26A0\uFE0F Not the cachly servers: API ${_}, sign-in ${i}
|
|
254
|
+
`);const a=Jo({argument:c("key"),credentials:Mo()});a||(console.log("No test key (cky_trial_\u2026) was found in ~/.cachly/credentials.json."),console.log("If you already use your own cachly account, there is nothing to claim."),console.log(`Otherwise pass the key: npx @cachly-dev/mcp-server@latest claim --key cky_trial_\u2026
|
|
255
255
|
`),process.exit(1));const g=a.schluessel,d={argument:"--key",credentials:"~/.cachly/credentials.json"}[a.quelle];console.log(`Test key: ${g.slice(0,14)}\u2026 (from ${d})
|
|
256
256
|
`);let l="";try{console.log(`Step 1: Sign in to your cachly account
|
|
257
|
-
`);const r=await
|
|
257
|
+
`);const r=await Yo(fetch,i);console.log(` Code: \x1B[1;33m${r.userCode}\x1B[0m`),console.log(" Open this URL and confirm the code:"),console.log(`${r.adresse}
|
|
258
258
|
`),ie(r.adresse,(m,f)=>{m||console.log(`
|
|
259
|
-
\u2139\uFE0F No browser could be opened here (${f??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await
|
|
259
|
+
\u2139\uFE0F No browser could be opened here (${f??"unknown"}) \u2014 please open the URL yourself.`)}),process.stdout.write(" Waiting for sign-in"),l=await Uo(fetch,r,{basis:i,puls:()=>process.stdout.write(".")}),console.log(` \x1B[32m\u2713\x1B[0m
|
|
260
260
|
`)}catch(r){console.error(`
|
|
261
261
|
|
|
262
262
|
${r.message}. Nothing was changed.
|
|
263
|
-
`),process.exit(1)}process.stdout.write("Step 2: Moving the test Brain into your account (it restarts once, up to a minute)\u2026");let p;try{p=await
|
|
263
|
+
`),process.exit(1)}process.stdout.write("Step 2: Moving the test Brain into your account (it restarts once, up to a minute)\u2026");let p;try{p=await Wo(fetch,_,l,g,"mcp",`cachly-mcp/${D}`),console.log(` \x1B[32m\u2713\x1B[0m
|
|
264
264
|
`)}catch(r){console.error(`
|
|
265
265
|
|
|
266
|
-
${
|
|
267
|
-
`),process.exit(1)}x=p.apiKey,te(p.apiKey),
|
|
266
|
+
${qo(r)}
|
|
267
|
+
`),process.exit(1)}x=p.apiKey,te(p.apiKey),tt(p.instanceId,{apiKey:p.apiKey}),await ge(p.apiKey),await fe(p.instanceId);const y=o(),w=new Set([...Object.values(be).map(r=>s(process.cwd(),r)),s(y,".claude.json"),s(y,".claude","mcp.json"),s(y,".cursor","mcp.json"),s(y,".codeium","windsurf","mcp_config.json")]);let b=0;for(const r of w)if(n(r))try{const m=Ko(await e(r,"utf-8"),g,p.apiKey);m.ersetzt&&(await t(r,m.text,"utf-8"),b++)}catch{}const u=await Fo(fetch,_,p.apiKey,p.instanceId);console.log(zo(p,u)),console.log(`
|
|
268
268
|
New key stored in ~/.cachly/credentials.json${b?` and in ${b} editor config file(s) that held the test key`:""}.`),console.log(`Restart your editor (or reload its MCP servers) so it uses the new key.
|
|
269
269
|
`),process.exit(0)}const ve=process.argv[2]==="autopilot";if(process.argv[2]==="autosetup"||process.argv[2]==="setup"||ve){const{writeFile:e,mkdir:t,readFile:n}=await import("node:fs/promises"),{existsSync:s}=await import("node:fs"),{resolve:o,dirname:c}=await import("node:path"),{createInterface:i}=await import("node:readline"),a=Date.now(),g=ve?"autopilot":"setup",d=process.argv.indexOf("--api-url");d!==-1&&process.argv[d+1]&&(_=process.argv[d+1].replace(/\/+$/,""),console.log(`\u2139\uFE0F Using self-hosted backend: ${_}
|
|
270
270
|
`)),C("setup_started");const l=process.stdin.isTTY===!0,p=ve||process.argv.includes("--yes")||process.argv.includes("-y")||!l;ve?console.log(`\u{1F916} Autopilot \u2014 one-command setup (auth \u2192 instance \u2192 configs \u2192 Brain), zero prompts.
|
|
@@ -301,7 +301,7 @@ Could not create an instance automatically. Opening ${N("/instances",g)} \u2026
|
|
|
301
301
|
`),ie(N("/instances",g)),y.close(),process.exit(1))}const r=u[0];u.length>1&&(console.log(`\u2139\uFE0F Multiple instances found \u2014 using most recent: ${r.name}`),console.log(` (Run with --instance-id <id> to use a different one)
|
|
302
302
|
`)),console.log(`\u2713 Instance: ${r.name} (${r.id.slice(0,8)}\u2026)
|
|
303
303
|
`),C("setup_instance_ready",{instance_id:r.id});const m=process.cwd(),f=[],{homedir:k}=await import("node:os"),B=k();f.push("claude"),s(o(m,".cursor"))&&f.push("cursor"),s(o(m,".windsurf"))&&f.push("windsurf"),s(o(m,".vscode"))&&f.push("copilot"),s(o(m,".continue"))&&f.push("continue");const T=process.platform==="darwin"?o(B,"Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"):o(B,".vscode/extensions");(s(T)&&!f.includes("copilot")||s(T))&&f.push("cline");const S=process.platform==="darwin"?o(B,"Library/Application Support/Zed"):o(B,".config/zed");s(S)&&f.push("zed");const I=h=>({claude:"Claude Code",cursor:"Cursor",windsurf:"Windsurf",copilot:"GitHub Copilot",continue:"Continue.dev",cline:"Cline (VSCode)",zed:"Zed"})[h]??h,E=f;console.log(`Step 3: Configuring for: ${E.map(I).join(", ")}
|
|
304
|
-
`);const{existsSync:M}=await import("node:fs"),v=[];let A=0;te(b);for(const h of E){const $=be[h]??".mcp.json",R=o(m,$);try{await t(c(R),{recursive:!0});const J=M(R),Y=await
|
|
304
|
+
`);const{existsSync:M}=await import("node:fs"),v=[];let A=0;te(b);for(const h of E){const $=be[h]??".mcp.json",R=o(m,$);try{await t(c(R),{recursive:!0});const J=M(R),Y=await Ct(R,b,r.id,h,{readFile:n,existsSync:M});await e(R,Y,"utf-8"),console.log(`\u2705 ${J?"Updated":"Written"}: ${$}`),A++}catch(J){const Y=J.message;console.log(`\u26A0\uFE0F Could not write ${$}: ${Y}`),console.log(" Fix permissions or run with sudo, then re-run setup."),v.push({file:$,reason:Y})}}const F=o(B,".claude","mcp.json");try{await t(c(F),{recursive:!0});let h={};if(s(F))try{h=JSON.parse(await n(F,"utf-8"))}catch{}h.mcpServers??={},h.mcpServers.cachly={command:"npx",args:["-y","@cachly-dev/mcp-server@latest"],env:oe(b,r.id,{includeApiKey:!0})},await e(F,JSON.stringify(h,null,2),"utf-8"),console.log("\u2705 Written: ~/.claude/mcp.json (global \u2014 works in every project)"),A++}catch(h){const $=h.message;console.log(`\u26A0\uFE0F Could not write ~/.claude/mcp.json: ${$}`),v.push({file:"~/.claude/mcp.json",reason:$})}const z=await At(m,r.id);for(const[h,$]of Object.entries(z))console.log(`${$==="updated"?"\u2705 Updated":$==="appended"?"\u2705 Appended to":"\u2705 Written"}: ${h}`);x=b;let ne=0;if(s(o(m,".git"))){process.stdout.write("\u23F3 Bootstrapping Brain from git history (~10s)...");try{const h=await U("brain_from_git",{instance_id:r.id,repo_path:m,limit:100}),$=h.match(/Ingested: \*\*(\d+)\*\*/);ne=$?parseInt($[1],10):0,console.log(` \u2713 ${ne} lesson${ne===1?"":"s"} extracted from git history`);const R=Co(h);R&&(console.log(""),console.log(R))}catch(h){console.log(` (skipped: ${h.message.slice(0,80)})`)}}if(ne===0){process.stdout.write("\u{1F331} Seeding 16 universal engineering lessons (first recall works instantly)...");try{await U("brain_seed_starter",{instance_id:r.id}),console.log(" \u2713");try{const h=await U("smart_recall",{instance_id:r.id,query:"docker build slow"}),$=kn(h);$&&(console.log(""),console.log(So($.topic,$.what)))}catch{}}catch(h){console.log(` (skipped: ${h.message.slice(0,60)})`)}}process.stdout.write(`
|
|
305
305
|
\u23F3 Fetching your Brain health preview...`);try{const h=await fetch(`${_}/api/v1/instances/${r.id}/memory`,{headers:{Authorization:`Bearer ${b}`},signal:AbortSignal.timeout(6e3)});if(h.ok){const $=await h.json(),R=$.lesson_count??0,J=$.context_count??0,Y=Math.round($.iq_boost_pct??0),Z=R===0?"Intern \u{1F331}":R<10?"Junior Dev \u{1F527}":R<30?"Mid Dev \u26A1":R<60?"Senior Dev \u{1F9E0}":R<100?"Staff Eng \u{1F680}":"Principal Eng \u{1F3C6}";if(console.log(` \u2713
|
|
306
306
|
`),console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),console.log("\u2502 \u{1F9E0} Brain Health Report \u2502"),console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log(`\u2502 Lessons stored : ${String(R).padEnd(6)} \u2502 Level: ${Z.padEnd(20)}\u2502`),console.log(`\u2502 Context entries : ${String(J).padEnd(6)} \u2502 Quality score: ${String(Y).padEnd(3)}% \u2502`),R===0&&(console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),console.log("\u2502 Your Brain is empty and ready to learn. \u2502"),console.log("\u2502 After your first coding session it will contain: \u2502"),console.log("\u2502 \u2022 Lessons from every bug you fixed \u2502"),console.log("\u2502 \u2022 Your project's indexed files \u2502"),console.log("\u2502 \u2022 A session summary for next time \u2502")),console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),R>=5){process.stdout.write(`
|
|
307
307
|
\u23F3 Running predictive risk scan...`);try{const L=(await U("brain_predict",{instance_id:r.id,context:"starting a new development session"})).split(`
|
|
@@ -316,10 +316,10 @@ Could not create an instance automatically. Opening ${N("/instances",g)} \u2026
|
|
|
316
316
|
`),console.log(` team_assign_role(instance_id="${r.id}", handle="<teammate>", role="contributor", assigned_by="${$.trim()}")
|
|
317
317
|
`))}else console.log(` Skipped \u2014 run team_assign_role at any time.
|
|
318
318
|
`)}catch{}if(!p){const h=await w(" \u{1F4EC} Stay in the loop? Email for release notes [Enter to skip]: ");if(h&&h.includes("@"))try{await fetch(`${_}/api/newsletter/subscribe`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:h.trim().toLowerCase(),source:"mcp-setup"}),signal:AbortSignal.timeout(5e3)}),console.log(` \u2705 Subscribed \u2014 you'll only hear from us when it matters.
|
|
319
|
-
`)}catch{}}try{const h=await
|
|
319
|
+
`)}catch{}}try{const h=await Ge(process.cwd(),r.id,b||void 0);h==="written"?console.log(`
|
|
320
320
|
\u2705 CLS git hook installed \u2014 your brain will learn from every commit.`):h==="upgraded"?console.log(`
|
|
321
|
-
\u2705 CLS git hook upgraded to ${
|
|
322
|
-
\u2705 CLS git hook appended to existing post-commit.`)}catch{}if(E.includes("claude"))try{const h=await
|
|
321
|
+
\u2705 CLS git hook upgraded to ${Ve}.`):h==="appended"&&console.log(`
|
|
322
|
+
\u2705 CLS git hook appended to existing post-commit.`)}catch{}if(E.includes("claude"))try{const h=await Ze(process.cwd(),r.id),$=h.scripts==="written"?"\u2705 Written":h.scripts==="upgraded"?`\u2705 Upgraded (\u2192 ${Qe})`:"\u2713 Unchanged";console.log(`${$}: .claude/hooks/ (Ambient Recall \u2014 session briefing, per-prompt recall, file briefing, auto-learn)`),h.settings==="written"?console.log("\u2705 Written: .claude/settings.json (Ambient Recall hooks wired)"):h.settings==="merged"?console.log("\u2705 Merged: .claude/settings.json (Ambient Recall hooks wired)"):console.log("\u2713 Ambient Recall hooks already wired in .claude/settings.json")}catch{}E.includes("cursor")&&await ue("cursor",process.cwd(),r.id," "),E.includes("copilot")&&await ue("copilot",process.cwd(),r.id," "),(s(o(B,".codex"))||s(o(m,".codex")))&&await ue("codex",process.cwd(),r.id," "),(s(o(B,".gemini"))||s(o(m,".gemini")))&&await ue("gemini",process.cwd(),r.id," "),x=b;const Re=Math.round((Date.now()-a)/1e3);if(v.length>0&&C("setup_config_write_failed",{instance_id:r.id,failed:v.length,succeeded:A}),C("setup_completed",{instance_id:r.id,elapsed_s:Re,config_failures:v.length}),v.length>0&&A===0){console.log(`
|
|
323
323
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`),console.log("\u2551 \u26A0\uFE0F Setup incomplete \u2014 no editor config was written \u2551"),console.log("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),console.log(`
|
|
324
324
|
Your Brain instance exists, but no editor knows about it yet.`),console.log(" Failed writes:");for(const h of v)console.log(` \u2022 ${h.file} \u2014 ${h.reason}`);console.log(`
|
|
325
325
|
Fix the permissions above and re-run, or configure manually:`),console.log(` CACHLY_JWT=${b.slice(0,12)}\u2026 CACHLY_BRAIN_INSTANCE_ID=${r.id}`),console.log(` Docs: ${N("/docs/mcp",g)}
|
|
@@ -343,13 +343,13 @@ Could not create an instance automatically. Opening ${N("/instances",g)} \u2026
|
|
|
343
343
|
\u2705 Brain learned from your commits.
|
|
344
344
|
`),await new Promise(a=>setTimeout(a,300))}catch(i){console.error(`
|
|
345
345
|
\u274C learn-git failed: ${i.message}
|
|
346
|
-
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await
|
|
346
|
+
`),process.exit(1)}process.exit(0)}if(process.argv[2]==="ambient-recall"&&await Lo(process.argv.slice(3),process.argv[1]),process.argv[2]==="ambient-auffrischen"&&await Bo(),process.argv[2]==="ambient-credit"){try{const e=Math.round(Number(process.argv[3]));if(Number.isFinite(e)&&e>0){const t=Math.min(e,2e4),n=process.argv.slice(4).join(" ").slice(0,200)||void 0,s={ts:new Date().toISOString(),event:"credit",injected:0,prevented:t,note:n};await Ho(s),await In(process.env.CACHLY_BRAIN_INSTANCE_ID??j,s),console.log(`\u2705 ambient credit recorded: ${t} tokens${n?` (${n})`:""}`)}else console.error("Usage: npx @cachly-dev/mcp-server@latest ambient-credit <tokens-saved> [note]")}catch{}process.exit(0)}if(process.argv[2]==="ambient-stats"){const e=await Xe(),t=_n(e),n=e.slice(-5);if(console.log(`
|
|
347
347
|
\u{1F9E0} Ambient Recall \u2014 net-token ledger
|
|
348
348
|
`),console.log(` Turns recorded: ${e.length}`),console.log(` Injected tokens: ${t.injected}`),console.log(` Prevented tokens: ${t.prevented} (agent-reported via ambient-credit)`),console.log(` NET: ${t.net>=0?"+":""}${t.net} tokens`),n.length>0){console.log(`
|
|
349
|
-
Last entries:`);for(const s of n){const o=s.prevented>0?`+${s.prevented} prevented`:`-${s.injected} injected`;console.log(` \u2022 ${s.ts.slice(0,19)} ${s.event}: ${o}${s.note?` (${s.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:i,checkHooks:a,checkLedger:g,renderDoctorReport:d,doctorExitCode:l}=await import("./doctor.js"),p=[e(),t(x),await n(_),await s(_,x),o(process.env.CACHLY_BRAIN_INSTANCE_ID??j),await c(_,x,process.env.CACHLY_BRAIN_INSTANCE_ID??j),a(i(process.cwd())),g(await
|
|
349
|
+
Last entries:`);for(const s of n){const o=s.prevented>0?`+${s.prevented} prevented`:`-${s.injected} injected`;console.log(` \u2022 ${s.ts.slice(0,19)} ${s.event}: ${o}${s.note?` (${s.note})`:""}`)}}console.log(""),process.exit(0)}if(process.argv[2]==="doctor"){const{checkNodeVersion:e,checkCredential:t,checkApiReachable:n,checkAuthAccepted:s,checkInstance:o,checkVectorCoverage:c,inspectAmbientHooks:i,checkHooks:a,checkLedger:g,renderDoctorReport:d,doctorExitCode:l}=await import("./doctor.js"),p=[e(),t(x),await n(_),await s(_,x),o(process.env.CACHLY_BRAIN_INSTANCE_ID??j),await c(_,x,process.env.CACHLY_BRAIN_INSTANCE_ID??j),a(i(process.cwd())),g(await Xe(),Po())];console.log(d(p)),process.exit(l(p))}if(process.argv[2]==="cls-ingest"){try{const e=process.argv[3];(!e||!x)&&process.exit(0);let t;try{t=JSON.parse(e)}catch{process.exit(0)}const n=t.instance_id??j;(!n||!t.source)&&process.exit(0),await U("cls_ingest",{instance_id:n,source:t.source,payload:t.payload??{}})}catch{}process.exit(0)}if(!x){const e=Rt();if(e)try{const t=await fetch(Lt(e),{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:Nt(e),signal:AbortSignal.timeout(8e3)});if(t.ok){const n=await t.json();n.access_token&&(x=n.access_token,ce(n.access_token),C("m2m_auth_completed",{grant:"client_credentials",client_id:e.clientId}),process.stderr.write(`\u{1F916} cachly: authenticated via client_credentials (M2M, headless).
|
|
350
350
|
`))}else process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth failed (${t.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.
|
|
351
351
|
`),C("m2m_auth_failed",{status:t.status})}catch(t){process.stderr.write(`\u26A0\uFE0F cachly: client_credentials auth error: ${t.message}
|
|
352
|
-
`),C("m2m_auth_failed",{reason:"network"})}}const
|
|
352
|
+
`),C("m2m_auth_failed",{reason:"network"})}}const qn=["demo","share","publish","health","autosetup","setup","autopilot","init","digest","invite","badge","join","upgrade","bench","tool-specs","openapi","ambient-credit","ambient-stats","doctor"];if(!x&&!qn.includes(process.argv[2]??""))if(!process.argv[2]&&process.stdout.isTTY===!0&&Dt){const s=`
|
|
353
353
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
354
354
|
\u2551 \u{1F9E0} cachly AI Brain \u2014 Setup required \u2551
|
|
355
355
|
\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
|
|
@@ -369,7 +369,7 @@ Could not create an instance automatically. Opening ${N("/instances",g)} \u2026
|
|
|
369
369
|
\u{1F9E0} cachly: no API key yet \u2014 the first cachly tool call creates a test Brain on EU servers, no sign-up.
|
|
370
370
|
(Own account: npx @cachly-dev/mcp-server@latest autopilot)
|
|
371
371
|
|
|
372
|
-
`);else{const e=
|
|
372
|
+
`);else{const e=Tt(x);if(e!==null){const t=Math.floor((e-Date.now())/6e4);t<=0?process.stderr.write(`
|
|
373
373
|
\u26A0\uFE0F cachly: CACHLY_JWT expired ${Math.abs(t)} minute(s) ago.
|
|
374
374
|
All tool calls will fail. Get a fresh token at ${N("/setup-ai","jwt-expiry")}
|
|
375
375
|
|
|
@@ -377,7 +377,7 @@ Could not create an instance automatically. Opening ${N("/instances",g)} \u2026
|
|
|
377
377
|
\u26A0\uFE0F cachly: CACHLY_JWT expires in ${t} minute(s).
|
|
378
378
|
Refresh it soon at ${N("/setup-ai","jwt-expiry")} to avoid interruptions.
|
|
379
379
|
|
|
380
|
-
`)}}process.env.PORT||
|
|
380
|
+
`)}}process.env.PORT||cn({aktuelle:an(D)});const we=process.env.PORT?parseInt(process.env.PORT,10):void 0;if(we){const{createServer:e}=await import("node:http");e((n,s)=>{const o=new URL(n.url??"/",`http://localhost:${we}`);if(o.pathname==="/health"){s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify({status:"ok",version:D,zeroResults:{total:uo,last10:po.slice(-10).map(c=>({query:c.query,ts:new Date(c.ts).toISOString()}))}}));return}if(o.pathname==="/mcp"||o.pathname==="/"){(async()=>{const c=Dn(),i=new Yt({sessionIdGenerator:void 0});s.on("close",()=>{i.close().catch(()=>{}),c.close().catch(()=>{})});try{await c.connect(i),await i.handleRequest(n,s)}catch(a){process.stderr.write(`cachly-mcp HTTP: ${a.message}
|
|
381
381
|
`),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:a.message})))}})();return}s.writeHead(404),s.end("not found")}).listen(we,()=>{process.stderr.write(`cachly-mcp HTTP server listening on :${we}
|
|
382
|
-
`)})}else{const e=new
|
|
383
|
-
`),(async()=>{await Ie().catch(()=>{});for(const[,s]of ee)await s.quit().catch(()=>{});process.exit(0)})()}))}Be("cachly","startup",{version:D,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{
|
|
382
|
+
`)})}else{const e=new Jt;W("start: Module geladen, stdio verbinden"),await G.connect(e),typeof process.argv[2]=="string"&&!process.argv[2].startsWith("-")||(Ue=!0,un(),dn(process.stdin,n=>{process.stderr.write(`[cachly-mcp] ${n} \u2014 Session zu Ende, Server geht mit
|
|
383
|
+
`),(async()=>{await Ie().catch(()=>{});for(const[,s]of ee)await s.quit().catch(()=>{});process.exit(0)})()}))}Be("cachly","startup",{version:D,mode:process.env.MCP_HTTP_PORT?"http":"stdio"}).catch(()=>{});export{xt as CLAUDE_MD_MARKER_END,Ee as CLAUDE_MD_MARKER_START,lo as CROSS_LINGUAL_MAP,be as EDITOR_FILES,ro as STOPWORDS,ao as arabicLightStem,St as buildClaudeMdBlock,Un as buildMcpConfig,oe as buildServerEnv,co as expandCrossLingual,so as extractTimestamp,io as katakanaToRomaji,oo as levenshtein,Yn as mcpAddBefehl,Ct as mergeMcpConfig,no as recencyBoost,mo as reconnectOnce,to as splitMultiQuery,Vt as startBackgroundDevicePoll,eo as tokenize,At as writeInstructions};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const E=75,o=.5,t=.7,L="qwen3-embedding:0.6b",_=1,N=.8,I=.9,e=1,n=.35,c=.35,p=.05,r=1,s=1,x=25,G=
|
|
1
|
+
const E=75,o=.5,t=.7,L="qwen3-embedding:0.6b",_=1,N=.8,I=.9,e=1,n=.35,c=.35,p=.05,r=1,s=1,x=25,G=15,T=2500,S=1500,C=.5,H=.5;export{p as ABLEHN_ABSTAND,c as CKG_BELEG_SCHWELLE,C as EINBLENDUNG_DECKUNG,H as EINBLENDUNG_ZEUGE,o as EINGANG_SCHWELLE,t as EINGANG_SORTIER_GEWICHT,s as LESER_GEWICHT,S as LESER_MAX_ZEICHEN,x as LESER_TIEFE,G as LESER_TIEFE_EINBLENDUNG,T as LESER_ZEITLIMIT_MS,I as NAHDUPLIKAT_SCHWELLE,r as SELTENHEIT_LAENGE_B,n as SINN_BELEG_SCHWELLE,E as SINN_TOPF,e as WORT_BELEG_SCHWELLE,_ as ZWEIT_GEWICHT,N as ZWEIT_MINDESTDECKUNG,L as ZWEIT_MODELL};
|
package/dist/src/startwissen.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import{execFile as A}from"node:child_process";import{homedir as
|
|
2
|
-
`)}let
|
|
3
|
-
`),t.startvorrat&&
|
|
1
|
+
import{execFile as A}from"node:child_process";import{homedir as T}from"node:os";import{basename as k,isAbsolute as N,relative as z,resolve as d}from"node:path";import{safeJsonParse as v,scanKeys as m}from"./utils.js";import{STARTER_CORPUS_SIZE as P}from"./starter-corpus.js";import{NAME_VEKTOR_PRAEFIX as C,VEKTOR_NACHTRAG as $,VEKTOR_PRAEFIX as D,ZWEIT_VEKTOR_PRAEFIX as L,packe as S,textFuerNamensVektor as M,textFuerVektor as x}from"./bedeutung.js";const u="cachly:startwissen:git",E=30,I=1500,F=1e3,K=3,_=90*86400,B=P;function G(t=process.env){return!/^(0|false|off|no|nein)$/i.test((t.CACHLY_STARTVORRAT??"").trim())}const b=t=>new Promise(e=>setTimeout(e,t));function at(t){for(const n of t.wurzeln??[])if(n.uri.startsWith("file:"))try{return t.dateiPfad(n.uri)}catch{}const e=t.env??{};for(const n of["CLAUDE_PROJECT_DIR","CACHLY_WORKSPACE"]){const r=(e[n]??"").trim();if(r&&!r.includes("${"))return r}return t.cwd}function J(t,e){const n=z(e,t);return n===""||!n.startsWith("..")&&!N(n)}function X(t,e){return process.platform==="win32"?t.toLowerCase()===e.toLowerCase():t===e}function U(t,e=process.env){const n=d(t),r=(e.CLAUDE_PLUGIN_ROOT??"").trim();if(r&&!r.includes("${")&&J(n,d(r)))return"plugin-ordner";if(n.split(/[\\/]+/).some(c=>c==="node_modules"||c==="_npx"))return"paketordner";const s=e.HOME||e.USERPROFILE||T();return s&&X(n,d(s))?"heimordner":""}function V(t){return new Promise(e=>{try{A("git",["rev-parse","--show-toplevel"],{cwd:t,timeout:5e3,windowsHide:!0},(n,r)=>{const s=String(r??"").trim();e(n||!s?"":d(s))})}catch{e("")}})}function W(t,e){return["","","---",`\u2139\uFE0F **cachly:** this new Brain just learned ${t} lesson${t===1?"":"s"} from the git history of \`${k(e)}\` (last ${E} commits at most). \`smart_recall\` finds them now. Tell the user once.`].join(`
|
|
2
|
+
`)}let w="";function ot(){const t=w;return w="",t}async function j(t){const e=t.protokoll??(r=>{process.stderr.write(r)}),n=t.env??process.env;try{const r=d(await t.projektOrdner()),s=await(t.gitWurzel??V)(r);if(!s)return e(`cachly: ${r} is not a git repository \u2014 the new Brain starts without git history.
|
|
3
|
+
`),t.startvorrat&&G(n)?await Z(t,r,e):{art:"kein-repo",ordner:r};const c=U(s,n);if(c)return e(`cachly: ${s} is not a user project (${c}) \u2014 no import from git history.
|
|
4
4
|
`),{art:"ausgeschlossen",ordner:s,grund:c};const o=await t.verbindung(t.instanzId);if((await m(o,"cachly:lesson:best:*",{max:1})).length>0)return e(`cachly: this Brain already has lessons \u2014 no import from git history.
|
|
5
|
-
`),{art:"hat-lektionen"};if(await o.set(u,JSON.stringify({stand:"laeuft",seit:new Date().toISOString(),ordner:s}),"NX")!=="OK")return{art:"schon-erledigt"};e(`cachly: new Brain \u2014 learning from the last ${
|
|
6
|
-
`);const i=Date.now();try{await t.ausGit({instance_id:t.instanzId,repo_path:s,limit:
|
|
7
|
-
`),{art:"fehler",grund:f}}const a=[];for(const
|
|
8
|
-
`),a.length>0&&(
|
|
9
|
-
`),{art:"fehler",grund:s}}}function
|
|
10
|
-
`)}async function
|
|
11
|
-
`),{art:"hat-lektionen"};if(await s.set(u,JSON.stringify({stand:"startvorrat",seit:new Date().toISOString(),ordner:e}),"NX")!=="OK")return{art:"schon-erledigt"};
|
|
12
|
-
`);try{await
|
|
13
|
-
`),{art:"fehler",grund:a}}const o=[];for(const i of await m(s,"cachly:lesson:best:*",{max:1e3})){const a=
|
|
14
|
-
`),o.length>0&&(
|
|
15
|
-
`);break}}return
|
|
16
|
-
`),
|
|
5
|
+
`),{art:"hat-lektionen"};if(await o.set(u,JSON.stringify({stand:"laeuft",seit:new Date().toISOString(),ordner:s}),"NX")!=="OK")return{art:"schon-erledigt"};e(`cachly: new Brain \u2014 learning from the last ${E} commits of ${s} in the background.
|
|
6
|
+
`);const i=Date.now();try{await t.ausGit({instance_id:t.instanzId,repo_path:s,limit:E})}catch(h){const f=h instanceof Error?h.message:String(h);return await o.set(u,JSON.stringify({stand:"abgebrochen",am:new Date().toISOString(),grund:f.slice(0,200)})).catch(()=>{}),e(`cachly: import from git history failed: ${f}
|
|
7
|
+
`),{art:"fehler",grund:f}}const a=[];for(const h of await m(o,"cachly:lesson:best:*",{max:1e3})){const f=v(await o.get(h),{});(Array.isArray(f.tags)?f.tags:[]).includes("brain_from_git")&&a.push({topic:h.slice(19),lektion:f})}await o.set(u,JSON.stringify({stand:"fertig",am:new Date().toISOString(),ordner:s,lektionen:a.length})).catch(()=>{});const g=((Date.now()-i)/1e3).toFixed(1);e(`cachly: learned ${a.length} lessons from git history in ${g} s.
|
|
8
|
+
`),a.length>0&&(w=W(a.length,s));try{t.melde?.(a.length)}catch{}const p=await R(o,a,t,e);return{art:"fertig",ordner:s,lektionen:a.length,vektoren:p}}catch(r){const s=r instanceof Error?r.message:String(r);return e(`cachly: import from git history stopped: ${s}
|
|
9
|
+
`),{art:"fehler",grund:s}}}function H(t){return["","","---",`\u2139\uFE0F **cachly:** the project folder is not a git repository, so this new Brain loaded ${t} starter lesson${t===1?"":"s"} (common engineering fixes, tagged \`source: "starter"\`; they never override own lessons). \`smart_recall\` finds them now. Tell the user once.`].join(`
|
|
10
|
+
`)}async function Z(t,e,n){const r=t.startvorrat;if(!r)return{art:"kein-repo",ordner:e};const s=await t.verbindung(t.instanzId);if((await m(s,"cachly:lesson:best:*",{max:1})).length>0)return n(`cachly: this Brain already has lessons \u2014 no starter lessons.
|
|
11
|
+
`),{art:"hat-lektionen"};if(await s.set(u,JSON.stringify({stand:"startvorrat",seit:new Date().toISOString(),ordner:e}),"NX")!=="OK")return{art:"schon-erledigt"};n(`cachly: new Brain without git history \u2014 loading ${B} starter lessons in the background.
|
|
12
|
+
`);try{await r({instance_id:t.instanzId})}catch(i){const a=i instanceof Error?i.message:String(i);return await s.set(u,JSON.stringify({stand:"abgebrochen",am:new Date().toISOString(),grund:a.slice(0,200)})).catch(()=>{}),n(`cachly: loading starter lessons failed: ${a}
|
|
13
|
+
`),{art:"fehler",grund:a}}const o=[];for(const i of await m(s,"cachly:lesson:best:*",{max:1e3})){const a=v(await s.get(i),{});a.source==="starter"&&o.push({topic:i.slice(19),lektion:a})}await s.set(u,JSON.stringify({stand:"fertig",am:new Date().toISOString(),ordner:e,startvorrat:o.length})).catch(()=>{}),n(`cachly: loaded ${o.length} starter lessons.
|
|
14
|
+
`),o.length>0&&(w=H(o.length));try{t.meldeStartvorrat?.(o.length)}catch{}const l=await R(s,o,t,n);return{art:"startvorrat",ordner:e,lektionen:o.length,vektoren:l}}async function R(t,e,n,r){const s=n.einbetten;if(!s||e.length===0||!(n.hatEinbettung??(()=>!0))())return 0;for(const{topic:a}of e)await t.sadd($,a).catch(()=>{});const c=n.schlafen??b,o=n.pauseMs??I;let l=0,i=0;for(const{topic:a,lektion:g}of e)try{await c(o);const p=await s(x({...g,topic:a}));p?.length&&(await t.set(`${D}${a}`,S(p),"EX",_),await t.srem($,a),l++),await c(o);const h=await s(M(a));h?.length&&await t.set(`${C}${a}`,S(h),"EX",_),i=0}catch{if(i++,i>=K){r(`cachly: embedding service unavailable \u2014 ${e.length-l} lessons wait in the backlog; smart_recall fills them in later.
|
|
15
|
+
`);break}}return r(`cachly: search vectors for git lessons: ${l}/${e.length}.
|
|
16
|
+
`),l>0&&await Y(t,e,n,r),l}async function Y(t,e,n,r){const s=n.einbettenZweit;if(!s)return 0;const c=n.schlafen??b,o=n.pauseMs??I;let l=0;for(const{topic:i,lektion:a}of e)try{await c(o);const g=await s(x({...a,topic:i}));g?.length&&(await t.set(`${L}${i}`,S(g),"EX",_),l++)}catch{break}return r(`cachly: second-model vectors for git lessons: ${l}/${e.length}.
|
|
17
|
+
`),l}const y=new Map,O=new Map;function it(t){return O.get(t)}function ct(t){const e=y.get(t.instanzId);if(e)return e;const n=(async()=>(await(t.schlafen??b)(t.anlaufMs??F),j(t)))().catch(r=>({art:"fehler",grund:r instanceof Error?r.message:String(r)})).then(r=>(O.set(t.instanzId,r.art),r));return y.set(t.instanzId,n),n}function lt(t){return y.has(t)}async function ht(t,e){return await t.set(u,JSON.stringify({stand:e,seit:new Date().toISOString()}),"NX")==="OK"}function ft(){y.clear(),O.clear(),w=""}export{F as ANLAUF_MS,I as EINBETT_PAUSE_MS,B as STARTVORRAT_LEKTIONEN,E as STARTWISSEN_COMMITS,u as STARTWISSEN_MARKE,ft as _startwissenZuruecksetzen,U as ausschlussGrund,ht as beanspruchStartwissen,V as echteGitWurzel,ot as holeStartwissenHinweis,j as lerneAusGitGeschichte,ct as starteStartwissen,G as startvorratErlaubt,H as startvorratSatz,it as startwissenAusgang,lt as startwissenGestartet,W as startwissenSatz,at as waehleProjektOrdner};
|
package/glama.json
CHANGED
|
@@ -15,7 +15,7 @@ ${e}
|
|
|
15
15
|
</${se}>`:""}var Cn=/(?:^|__)(learn_from_attempts|remember_context|session_end|session_handoff|team_learn|global_learn|auto_learn_session)$/,In=/^\s*(✋|⛔|Error\b|Fehler\b|Update abgewiesen|Rejected)/i,at=/\bBeleg:\s*`?([0-9a-f]{8})`?/gi,Nn=[/\b(lektion(en)?|lesson|brain|gedaechtnis|gedächtnis|memory|cachly)\b[^.\n]{0,80}\b(gespeichert|abgelegt|eingetragen|festgehalten|hinterlegt|geschrieben|stored|saved|recorded|persisted)\b/i,/\b(gespeichert|abgelegt|eingetragen|festgehalten|hinterlegt|geschrieben|stored|saved|recorded|persisted|learned)\b[^.\n]{0,40}\b(im|ins|in the|to the|to|into)\s+(brain|gedaechtnis|gedächtnis|memory)\b/i,/\b(als|as an?)\s+(?!(?:die|der|das|den|dem|the)\b)(?:[\wäöüß-]+\s+){0,2}(lektion|lesson)\b/i];var zn=/\?\s*$|\b(soll ich|kann ich|darf ich|moechtest|möchtest|willst|wenn du|falls du|shall i|should i|would you|want me to|if you)\b/i,ut="(?:die ki|das modell|der agent|der assistent|the (?:ai|model|agent|assistant)|claude)",ct="(?:wenn|ob|falls|dass|behauptet|if|whether|claims?|says?)",Tn=new RegExp(`\\b${ut}\\b[^.\\n]*?\\b${ct}\\b|\\b${ct}\\b[^.\\n]*?\\b${ut}\\b`,"i"),Rn=/„[^“”"\n]*[“”"]|“[^”\n]*”|"[^"\n]*"|»[^«\n]*«|«[^»\n]*»|‚[^‘’\n]*[‘’]|(?<![\p{L}\p{N}])'[^'\n]*'(?![\p{L}\p{N}])/gu,Pn=/\b(sei|seien)\b|\b(sagt|sagte|meint|meinte|schreibt|schrieb|behauptet)\s+(er|sie|es|man)\b|\blaut\b|\baccording to\b|\b(he|she|they)\s+(says?|said|claims?|claimed|wrote)\b/i;function On(t){return t.replace(Rn," ")}function jn(t){return t.split(/\n+/).filter(e=>!e.trim().startsWith("|")).map(On).flatMap(e=>e.split(/(?<=[.!?])\s+/)).some(e=>!zn.test(e)&&!Tn.test(e)&&!Pn.test(e)&&Nn.some(n=>n.test(e)))}function oe(t){let e=t.message?.content;return typeof e=="string"?[{type:"text",text:e}]:Array.isArray(e)?e:[]}function Mn(t){return typeof t.content=="string"?t.content:Array.isArray(t.content)?t.content.map(e=>typeof e?.text=="string"?e.text:"").join(`
|
|
16
16
|
`):""}function Hn(t){if(t.type!=="user"||t.isMeta||t.origin?.kind&&t.origin.kind!=="human")return!1;let e=oe(t).filter(n=>n.type==="text").map(n=>n.text??"").join("");return e?!/^\s*<(task-notification|local-command|command-name|system-reminder)/.test(e):!1}function Wn(t){let e=[];for(let l of t)if(l.trim())try{let d=JSON.parse(l);d&&!d.isSidechain&&(d.type==="user"||d.type==="assistant")&&e.push(d)}catch{}let n=0;for(let l=e.length-1;l>=0;l--)if(Hn(e[l])){n=l+1;break}let r=e.slice(n),o=new Set,s="";for(let l of r)if(l.type==="assistant")for(let d of oe(l))d.type==="text"&&d.text&&(s+=`${d.text}
|
|
17
17
|
`),d.type==="tool_use"&&d.id&&Cn.test(d.name??"")&&o.add(d.id);let c=0,a="";for(let l of r)if(l.type==="user")for(let d of oe(l)){if(d.type!=="tool_result")continue;let f=Mn(d);a+=`${f}
|
|
18
|
-
`,d.tool_use_id&&o.has(d.tool_use_id)&&!d.is_error&&!In.test(f)&&c++}let g=new Set([...a.matchAll(at)].map(l=>l[1].toLowerCase())),u=[...s.matchAll(at)].map(l=>l[1].toLowerCase()),i=[...new Set(u.filter(l=>!g.has(l)))];return{behauptet:jn(s),schreibaufrufe:o.size,erfolgreich:c,erfundeneBelege:i}}function ie(t,e){if(e)return"";let n=Wn(t),r=[];return n.erfundeneBelege.length&&r.push(`Die Antwort nennt Beleg ${n.erfundeneBelege.join(", ")}, den kein cachly-Werkzeug in diesem Zug ausgegeben hat.`),n.behauptet&&n.erfolgreich===0&&r.push(n.schreibaufrufe>0?"Die Antwort meldet eine Speicherung im Brain, aber der Schreibaufruf wurde abgewiesen oder schlug fehl.":"Die Antwort meldet eine Speicherung im Brain, aber in diesem Zug lief kein Schreibaufruf (learn_from_attempts, remember_context, session_end)."),r.length?JSON.stringify({decision:"block",reason:`cachly Schreibbeleg: ${r.join(" ")} Speichere jetzt wirklich oder korrigiere die Aussage gegenueber dem Nutzer. Bezieht sich die Aussage auf eine fruehere Speicherung, sag das ausdruecklich.`}):""}var Fn=75,Kn=["topic","outcome","what_worked","what_failed","severity","confidence","recall_count","ts","endorsements"],lt=new Set("the a an and or but for to of in on at is are be do does did we you i it this that with without how what why when where can could would should please just get set use using make made need bitte und oder der die das ein eine f\xFCr mit ohne wie was warum kann soll noch mal auch von den dem ist weil wenn dann doch aber alle jede jeder jedes immer wieder wird werden wurde muss beim sehr nicht".split(/\s+/)),$n=["ierungen","ierung","ieren","iert","ungen","ung","heit","keit","lich","isch","ing","ed","en","er","es","e","n","s"];function Gn(t){for(let e of $n)if(t.length-e.length>=4&&t.endsWith(e))return t.slice(0,-e.length);return t}function ae(t){return[...new Set(String(t).toLowerCase().split(/[^a-z0-9]+/).filter(e=>e.length>3&&!lt.has(e)).map(Gn).filter(e=>!lt.has(e)))]}function Yn(t,e){let n=0;for(let r of t)e.includes(r)&&n++;return n}var F=class{constructor(e,{topf:n=Fn}={}){this.lektionen=e;this.topf=n,this.texte=e.map(o=>Re(o)),this.wortmengen=this.texte.map(o=>new Set([...W(o)].map(Te))),this.heuhaufen=this.texte.map(o=>o.toLowerCase()),this.statistik=new T(this.texte);let r=e.map((o,s)=>{let c=`cachly:lesson:best:${String(o.topic??s)}`;this.platzVonSchluessel.set(c,s);let a={};for(let g of Kn)o[g]!==void 0&&(a[g]=o[g]);return{key:c,content:JSON.stringify(a)}});this.wortbestand=rt(r)}lektionen;texte;wortmengen;heuhaufen;statistik;wortbestand;platzVonSchluessel=new Map;topf;get groesse(){return this.lektionen.length}sortiere(e){if(!this.wortbestand)return[];let n=st(this.wortbestand,e,this.topf),r=[],o=[];for(let u of n){let i=this.platzVonSchluessel.get(u.key);i!==void 0&&(r.push(i),o.push(u.score))}if(r.length===0)return[];let s=W(e),c=ae(e),a=Q(o),g=Q(r.map(u=>this.statistik.besterZeuge(s,this.wortmengen[u])));return r.map((u,i)=>({lektion:this.lektionen[u],punkte:a[i]+.5*this.statistik.deckung(s,this.wortmengen[u])+.5*g[i],belege:Yn(c,this.heuhaufen[u])})).sort((u,i)=>i.punkte-u.punkte||Number(i.lektion.recall_count??0)-Number(u.lektion.recall_count??0))}};var qn={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};var Vs=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3),Xs=Number(process.env.CACHLY_EMBED_TIMEOUT_MAX_MS??45e3);function Zn(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}var Qs=!!process.env.CACHLY_EMBED_PROVIDER,eo=(process.env.CACHLY_EMBED_PROVIDER??Zn()).toLowerCase();import{readFileSync as Jn,writeFileSync as Vn,renameSync as Xn,mkdirSync as Qn,rmSync as er}from"node:fs";import{dirname as tr}from"node:path";var K=3,ue=10*6e4,dt={fehlschlaege:0,offenBis:0};function ce(){return["0","off","aus","false"].includes(String(process.env.CACHLY_LESER_SICHERUNG??"").toLowerCase())}function nr(t){return t===503?"abgeschaltet":t>=500?"fehlschlag":"neutral"}function rr(t){return t?.name==="SyntaxError"?"neutral":"fehlschlag"}function gt(t){let e=t??{},n=r=>typeof r=="number"&&Number.isFinite(r)&&r>0?r:0;return{fehlschlaege:Math.floor(n(e.fehlschlaege)),offenBis:n(e.offenBis)}}var R=class{constructor(e,n=()=>Date.now()){this.speicher=e;this.jetzt=n}speicher;jetzt;offen(){if(ce())return!1;let e=this.speicher.lies();if(e.fehlschlaege<K)return!1;let n=this.jetzt();return n<e.offenBis&&e.offenBis-n<=ue}darfFragen(){if(ce())return!0;if(this.offen())return!1;let e=this.speicher.lies();return e.fehlschlaege>=K&&this.speicher.schreib({fehlschlaege:e.fehlschlaege,offenBis:this.jetzt()+ue}),!0}melde(e){if(e==="neutral"||ce())return;let n=this.speicher.lies();if(e==="erfolg"){(n.fehlschlaege!==0||n.offenBis!==0)&&this.speicher.schreib({...dt});return}let r=e==="abgeschaltet"?Math.max(n.fehlschlaege+1,K):n.fehlschlaege+1;this.speicher.schreib({fehlschlaege:r,offenBis:r>=K?this.jetzt()+ue:0})}},le={art:"ohne"};async function ge(t,e){if(!e.darfFragen())return{art:"uebersprungen"};let n=t.fetchFn??fetch;try{let r=await n(t.url,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.jwt}`,...t.zusatzKopf??{}},body:JSON.stringify({query:t.frage,texts:t.texte,instance_id:t.instanceId}),signal:AbortSignal.timeout(t.zeitlimitMs)});if(!r.ok)return e.melde(nr(r.status)),le;let o=await r.json(),s=Array.isArray(o?.scores)?o.scores:null;return!s||s.length!==t.texte.length||!s.every(c=>typeof c=="number"&&Number.isFinite(c))?le:(e.melde("erfolg"),{art:"punkte",scores:s,provider:typeof o.provider=="string"?o.provider:"?",ms:Number(o.ms)||0})}catch(r){return e.melde(rr(r)),le}}function ft(t){return{lies:()=>{try{return gt(JSON.parse(Jn(t,"utf8")))}catch{return{...dt}}},schreib:e=>{let n=`${t}.${process.pid}.tmp`;try{Qn(tr(t),{recursive:!0}),Vn(n,JSON.stringify(gt(e)),{mode:384}),Xn(n,t)}catch{try{er(n,{force:!0})}catch{}}}}}function ht(t,e,n=1){let r=c=>{let a=Math.min(...c),g=Math.max(...c);return g>a?c.map(u=>(u-a)/(g-a)):c.map(()=>0)},o=r(t),s=r(e);return t.map((c,a)=>({i:a,p:o[a]+n*s[a]})).sort((c,a)=>a.p-c.p||c.i-a.i).map(c=>c.i)}var pr=600*1e3,Et=8e3,hr=60*1e3,mt=120,_t=
|
|
18
|
+
`,d.tool_use_id&&o.has(d.tool_use_id)&&!d.is_error&&!In.test(f)&&c++}let g=new Set([...a.matchAll(at)].map(l=>l[1].toLowerCase())),u=[...s.matchAll(at)].map(l=>l[1].toLowerCase()),i=[...new Set(u.filter(l=>!g.has(l)))];return{behauptet:jn(s),schreibaufrufe:o.size,erfolgreich:c,erfundeneBelege:i}}function ie(t,e){if(e)return"";let n=Wn(t),r=[];return n.erfundeneBelege.length&&r.push(`Die Antwort nennt Beleg ${n.erfundeneBelege.join(", ")}, den kein cachly-Werkzeug in diesem Zug ausgegeben hat.`),n.behauptet&&n.erfolgreich===0&&r.push(n.schreibaufrufe>0?"Die Antwort meldet eine Speicherung im Brain, aber der Schreibaufruf wurde abgewiesen oder schlug fehl.":"Die Antwort meldet eine Speicherung im Brain, aber in diesem Zug lief kein Schreibaufruf (learn_from_attempts, remember_context, session_end)."),r.length?JSON.stringify({decision:"block",reason:`cachly Schreibbeleg: ${r.join(" ")} Speichere jetzt wirklich oder korrigiere die Aussage gegenueber dem Nutzer. Bezieht sich die Aussage auf eine fruehere Speicherung, sag das ausdruecklich.`}):""}var Fn=75,Kn=["topic","outcome","what_worked","what_failed","severity","confidence","recall_count","ts","endorsements"],lt=new Set("the a an and or but for to of in on at is are be do does did we you i it this that with without how what why when where can could would should please just get set use using make made need bitte und oder der die das ein eine f\xFCr mit ohne wie was warum kann soll noch mal auch von den dem ist weil wenn dann doch aber alle jede jeder jedes immer wieder wird werden wurde muss beim sehr nicht".split(/\s+/)),$n=["ierungen","ierung","ieren","iert","ungen","ung","heit","keit","lich","isch","ing","ed","en","er","es","e","n","s"];function Gn(t){for(let e of $n)if(t.length-e.length>=4&&t.endsWith(e))return t.slice(0,-e.length);return t}function ae(t){return[...new Set(String(t).toLowerCase().split(/[^a-z0-9]+/).filter(e=>e.length>3&&!lt.has(e)).map(Gn).filter(e=>!lt.has(e)))]}function Yn(t,e){let n=0;for(let r of t)e.includes(r)&&n++;return n}var F=class{constructor(e,{topf:n=Fn}={}){this.lektionen=e;this.topf=n,this.texte=e.map(o=>Re(o)),this.wortmengen=this.texte.map(o=>new Set([...W(o)].map(Te))),this.heuhaufen=this.texte.map(o=>o.toLowerCase()),this.statistik=new T(this.texte);let r=e.map((o,s)=>{let c=`cachly:lesson:best:${String(o.topic??s)}`;this.platzVonSchluessel.set(c,s);let a={};for(let g of Kn)o[g]!==void 0&&(a[g]=o[g]);return{key:c,content:JSON.stringify(a)}});this.wortbestand=rt(r)}lektionen;texte;wortmengen;heuhaufen;statistik;wortbestand;platzVonSchluessel=new Map;topf;get groesse(){return this.lektionen.length}sortiere(e){if(!this.wortbestand)return[];let n=st(this.wortbestand,e,this.topf),r=[],o=[];for(let u of n){let i=this.platzVonSchluessel.get(u.key);i!==void 0&&(r.push(i),o.push(u.score))}if(r.length===0)return[];let s=W(e),c=ae(e),a=Q(o),g=Q(r.map(u=>this.statistik.besterZeuge(s,this.wortmengen[u])));return r.map((u,i)=>({lektion:this.lektionen[u],punkte:a[i]+.5*this.statistik.deckung(s,this.wortmengen[u])+.5*g[i],belege:Yn(c,this.heuhaufen[u])})).sort((u,i)=>i.punkte-u.punkte||Number(i.lektion.recall_count??0)-Number(u.lektion.recall_count??0))}};var qn={apiUrl:process.env.CACHLY_API_URL??"https://api.cachly.dev",jwt:process.env.CACHLY_JWT??"",model:process.env.CACHLY_EMBED_MODEL??""};var Vs=Number(process.env.CACHLY_EMBED_TIMEOUT_MS??8e3),Xs=Number(process.env.CACHLY_EMBED_TIMEOUT_MAX_MS??45e3);function Zn(){return process.env.CACHLY_JWT?"cachly":process.env.OLLAMA_BASE_URL?"ollama":"none"}var Qs=!!process.env.CACHLY_EMBED_PROVIDER,eo=(process.env.CACHLY_EMBED_PROVIDER??Zn()).toLowerCase();import{readFileSync as Jn,writeFileSync as Vn,renameSync as Xn,mkdirSync as Qn,rmSync as er}from"node:fs";import{dirname as tr}from"node:path";var K=3,ue=10*6e4,dt={fehlschlaege:0,offenBis:0};function ce(){return["0","off","aus","false"].includes(String(process.env.CACHLY_LESER_SICHERUNG??"").toLowerCase())}function nr(t){return t===503?"abgeschaltet":t>=500?"fehlschlag":"neutral"}function rr(t){return t?.name==="SyntaxError"?"neutral":"fehlschlag"}function gt(t){let e=t??{},n=r=>typeof r=="number"&&Number.isFinite(r)&&r>0?r:0;return{fehlschlaege:Math.floor(n(e.fehlschlaege)),offenBis:n(e.offenBis)}}var R=class{constructor(e,n=()=>Date.now()){this.speicher=e;this.jetzt=n}speicher;jetzt;offen(){if(ce())return!1;let e=this.speicher.lies();if(e.fehlschlaege<K)return!1;let n=this.jetzt();return n<e.offenBis&&e.offenBis-n<=ue}darfFragen(){if(ce())return!0;if(this.offen())return!1;let e=this.speicher.lies();return e.fehlschlaege>=K&&this.speicher.schreib({fehlschlaege:e.fehlschlaege,offenBis:this.jetzt()+ue}),!0}melde(e){if(e==="neutral"||ce())return;let n=this.speicher.lies();if(e==="erfolg"){(n.fehlschlaege!==0||n.offenBis!==0)&&this.speicher.schreib({...dt});return}let r=e==="abgeschaltet"?Math.max(n.fehlschlaege+1,K):n.fehlschlaege+1;this.speicher.schreib({fehlschlaege:r,offenBis:r>=K?this.jetzt()+ue:0})}},le={art:"ohne"};async function ge(t,e){if(!e.darfFragen())return{art:"uebersprungen"};let n=t.fetchFn??fetch;try{let r=await n(t.url,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.jwt}`,...t.zusatzKopf??{}},body:JSON.stringify({query:t.frage,texts:t.texte,instance_id:t.instanceId}),signal:AbortSignal.timeout(t.zeitlimitMs)});if(!r.ok)return e.melde(nr(r.status)),le;let o=await r.json(),s=Array.isArray(o?.scores)?o.scores:null;return!s||s.length!==t.texte.length||!s.every(c=>typeof c=="number"&&Number.isFinite(c))?le:(e.melde("erfolg"),{art:"punkte",scores:s,provider:typeof o.provider=="string"?o.provider:"?",ms:Number(o.ms)||0})}catch(r){return e.melde(rr(r)),le}}function ft(t){return{lies:()=>{try{return gt(JSON.parse(Jn(t,"utf8")))}catch{return{...dt}}},schreib:e=>{let n=`${t}.${process.pid}.tmp`;try{Qn(tr(t),{recursive:!0}),Vn(n,JSON.stringify(gt(e)),{mode:384}),Xn(n,t)}catch{try{er(n,{force:!0})}catch{}}}}}function ht(t,e,n=1){let r=c=>{let a=Math.min(...c),g=Math.max(...c);return g>a?c.map(u=>(u-a)/(g-a)):c.map(()=>0)},o=r(t),s=r(e);return t.map((c,a)=>({i:a,p:o[a]+n*s[a]})).sort((c,a)=>a.p-c.p||c.i-a.i).map(c=>c.i)}var pr=600*1e3,Et=8e3,hr=60*1e3,mt=120,_t=15,mr=1500,St=2500,br=$(G(),"cachly-ambient-netlog.jsonl");function de(t){return dr("sha1").update(t).digest("hex").slice(0,12)}function yr(t){return $(G(),`cachly-ambient-bestand-${de(t)}.json`)}function kr(t){return $(G(),`cachly-leser-sicherung-${de(t)}.json`)}function wr(t){return $(G(),`cachly-ambient-auffrischen-${de(t)}.lock`)}async function bt(t,{fetchFn:e=fetch,zeitlimitMs:n=Et}={}){try{let r=await e(`${t.apiUrl}/api/v1/instances/${t.instanceId}/export`,{headers:{Authorization:`Bearer ${t.jwt}`},signal:AbortSignal.timeout(n)});if(!r.ok)return null;let o=await r.json();return Array.isArray(o?.lessons)?o.lessons.map(s=>typeof s=="string"?Er(s):s).filter(s=>!!s&&typeof s=="object"):null}catch{return null}}function Er(t){try{return JSON.parse(t)}catch{return null}}function yt(t,e){try{ur(gr(t),{recursive:!0}),wt(t,JSON.stringify({at:Date.now(),lessons:e}),{mode:384})}catch{}}function kt(t){try{let e=JSON.parse(ir(t,"utf8"));if(Array.isArray(e?.lessons))return{at:Number(e.at)||0,lessons:e.lessons}}catch{}return null}function _r(t,e){let n=wr(t.instanceId);try{if(ar(n)&&Date.now()-cr(n).mtimeMs<hr)return;wt(n,String(Date.now()),{mode:384})}catch{return}try{fr(process.execPath,e,{detached:!0,stdio:"ignore",env:{...process.env,CACHLY_API_URL:t.apiUrl,CACHLY_JWT:t.jwt,CACHLY_BRAIN_INSTANCE_ID:t.instanceId}}).unref()}catch{}}async function P(t,{force:e=!1,nebenlauf:n,abrufMs:r=Et,fetchFn:o}={}){if(!t.jwt||!t.instanceId)return{lessons:[],quelle:"nicht-eingerichtet"};let s=yr(t.instanceId);if(e){let g=await bt(t,{fetchFn:o,zeitlimitMs:r});if(g)return yt(s,g),{lessons:g,quelle:"server"};let u=kt(s);return u?{lessons:u.lessons,quelle:"platte-alt"}:{lessons:[],quelle:"server-nicht-erreichbar"}}let c=kt(s);if(c){let g=Date.now()-c.at<pr;return!g&&n&&_r(t,n),{lessons:c.lessons,quelle:g?"platte":"platte-alt"}}let a=await bt(t,{fetchFn:o,zeitlimitMs:r});return a?(yt(s,a),{lessons:a,quelle:"server"}):{lessons:[],quelle:"server-nicht-erreichbar"}}function O(t){return Math.ceil(String(t).length/4)}function fe(t){let e=t.severity?`[${t.severity}] `:"",n=String(t.what_worked??"").replace(/\s+/g," ").trim(),r=n.length>mt?`${n.slice(0,mt)}\u2026`:n;return`- ${e}${t.topic}: ${r}`}var Sr={lessons:[],tokens:0,topScore:0,belege:0};function vr(t,e,n){let r=[],o=0;for(let{lektion:s}of t.slice(0,e)){let c=O(fe(s));if(o+c>n)break;r.push(s),o+=c}return{lessons:r,tokens:o,topScore:Math.round(t[0].punkte*100)/100,belege:t[0].belege}}function xr(t){return Pe(t,mr)}async function Ar(t,e,n,{zeitlimitMs:r=St,fetchFn:o}={}){if(!t?.jwt||!t?.instanceId||n.length===0)return{art:"ohne"};if(["0","off","aus","false"].includes(String(process.env.CACHLY_LESER||"").toLowerCase()))return{art:"ohne"};let s=new R(ft(kr(t.instanceId)));return ge({url:`${t.apiUrl}/api/v1/rerank`,jwt:t.jwt,frage:e,texte:n,instanceId:t.instanceId,zeitlimitMs:r,fetchFn:o},s)}async function Lr(t,e,n,{minBelege:r=2,topK:o=3,tokenBudget:s=600,tiefe:c=_t,zeitlimitMs:a=St,fetchFn:g}={}){let u={...Sr,leser:"aus",leserMs:0};if(!Array.isArray(e)||e.length===0||ae(t).length===0)return u;let i=new F(e).sortiere(t).filter(f=>f.belege>=r);if(i.length===0)return u;let l="aus",d=0;if(i.length>1&&c>0){let f=i.slice(0,c),y=i.slice(c),_=await Ar(n,t,f.map(N=>xr(N.lektion)),{zeitlimitMs:a,fetchFn:g});_.art==="punkte"?(i=[...ht(f.map(v=>v.punkte),_.scores,1).map(v=>f[v]),...y],l=_.provider,d=_.ms):_.art==="uebersprungen"&&(l="uebersprungen")}return{...vr(i,o,s),leser:l,leserMs:d}}function Cr(t){if(!t.lessons.length)return"";let e=t.lessons.map(fe).join(`
|
|
19
19
|
`);return`\u{1F9E0} Cachly Brain \u2014 relevant lessons for this task (auto-recall, ${t.lessons.length}):
|
|
20
20
|
${D(e)}
|
|
21
21
|
(ambient-recall \xB7 ~${t.tokens} tokens \xB7 match score ${t.topScore})`}var Ir=5;function vt(t){if(!t.length)return"";let e=t.filter(o=>{let s=String(o.topic??"");return!(/^auto:/.test(s)||/^[a-z]+:?$/.test(s))}),r=[...e.length?e:t].sort((o,s)=>(Number(s.recall_count)||0)-(Number(o.recall_count)||0)).slice(0,Ir).map(fe).join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cachly-dev/mcp-server",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.184",
|
|
4
4
|
"mcpName": "io.github.cachly-dev/mcp-server",
|
|
5
5
|
"description": "Solve it once. From then on, your AI knows. Experience for coding agents, EU-hosted: 124 MCP tools for Claude Code, Cursor, Copilot & Windsurf. Learns from every bug fix, commit and CI run.",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
"url": "https://github.com/cachly-dev/cachly-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.10.
|
|
9
|
+
"version": "0.10.184",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"name": "@cachly-dev/mcp-server",
|
|
14
14
|
"identifier": "@cachly-dev/mcp-server",
|
|
15
|
-
"version": "0.10.
|
|
15
|
+
"version": "0.10.184",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|